﻿using Engine.Audio;
using Engine.Graphics;
using GameEntitySystem;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using TemplatesDatabase;
using XmlUtilities;

namespace Game
{
	//工作模式
	public enum WorkingMode
	{
		执行, 条件, 变量, 十亿伏特
	}

	//坐标类型
	public enum CoordinateMode
	{
		绝对, 相对, 玩家,
	}

	//坐标方向
	public enum CoordDirection
	{
		PX, PY, PZ, NX, NY, NZ
	}

	//指令提交结果
	public enum SubmitResult
	{
		Success, Fail, OutRange, Invalid, Limit, NoFound, Exception
	}

	//命令方块
	public class 命令方块 : CubeBlock, IElectricElementBlock, IPaintableBlock
	{
		public const int Index = 333;

		private Texture2D m_texture;

		public override void Initialize()
		{
			m_texture = ContentManager.Get<Texture2D>("Textures/Csharp6");
			EntityInfoManager.SetEntityInfos();
			CommandConfManager.Initialize();
			InstructionManager.Initialize();
			ManualTopicWidget.LoadInformationTopics();
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			generator.GenerateCubeVertices(this, value, x, y, z, Color.White, geometry.GetGeometry(m_texture).OpaqueSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData, m_texture);
		}

		public override int GetFaceTextureSlot(int face, int value)
		{
			switch (face)
			{
				case 4: return 1;
				case 5: return 1;
				default: return 0;
			}
		}

		public override int GetTextureSlotCount(int value)
		{
			return 2;
		}

		public ElectricElement CreateElectricElement(SubsystemElectricity subsystemElectricity, int value, int x, int y, int z)
		{
			Point3 position = new(x, y, z);
			return new CommandElectricElement(subsystemElectricity, position);
		}

		public int GetConnectionMask(int value)
		{
			return int.MaxValue;
		}

		public ElectricConnectorType? GetConnectorType(SubsystemTerrain terrain, int value, int face, int connectorFace, int x, int y, int z)
		{
			WorkingMode workingMode = GetWorkingMode(value);
			if (workingMode == WorkingMode.条件)
			{
				return ElectricConnectorType.Output;
			}
			else if (workingMode == WorkingMode.变量 && connectorFace == 4)
			{
				return ElectricConnectorType.Output;
			}
			return ElectricConnectorType.Input;
		}

		public static WorkingMode GetWorkingMode(int value)
		{
			int mode = Terrain.ExtractData(value) & 0xF;
			if (mode >= 8) mode = mode - 8;
			return (WorkingMode)mode;
		}

		public static int SetWorkingMode(int value, WorkingMode mode)
		{
			int typeValue = Terrain.ExtractData(value) & 0xF;
			typeValue = (typeValue + 8) % 16;
			if (GetWorkingMode(value) != mode) typeValue = (int)mode;
			int data = (Terrain.ExtractData(value) & -16) | (typeValue & 0xF);
			return Terrain.ReplaceData(value, data);
		}

		public int? GetPaintColor(int value)
		{
			return GetColor(Terrain.ExtractData(value));
		}

		public int Paint(SubsystemTerrain terrain, int value, int? color)
		{
			int data = Terrain.ExtractData(value);
			return Terrain.ReplaceData(value, SetColor(data, color));
		}

		public static int? GetColor(int data)
		{
			return (data >> 4) & 0xF;
		}

		public static int SetColor(int data, int? color)
		{
			if (color.HasValue)
			{
				return (data & -241) | ((color.Value & 0xF) << 4);
			}
			return data & -241;
		}
	}

	//命令辅助棒
	public class 命令辅助棒 : Block
	{
		public const int Index = 334;

		private Texture2D m_texture;

		private BlockMesh m_standaloneBlockMesh = new BlockMesh();

		public override void Initialize()
		{
			Model model = ContentManager.Get<Model>("Models/Stick");
			m_texture = ContentManager.Get<Texture2D>("Textures/Lightstick");
			Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Stick").ParentBone);
			m_standaloneBlockMesh.AppendModelMeshPart(model.FindMesh("Stick").MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0f, -0.5f, 0f), false, false, true, false, Color.White);
			base.Initialize();
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			BlocksManager.DrawMeshBlock(primitivesRenderer, m_standaloneBlockMesh, m_texture, color, 2f * size, ref matrix, environmentData);
		}
	}

	//命令方块行为
	public class SubsystemCommandBlockBehavior : SubsystemBlockBehavior, IDrawable
	{
		class Chartlet
		{
			public Vector3 Position;
			public Vector3 P1;
			public Vector3 P2;
			public Vector3 P3;
			public Vector3 P4;
			public Color Color;
			public WorkingMode WorkingMode;
		}

		public override int[] HandledBlocks => [命令方块.Index];

		private Dictionary<Point3, CommandData> m_commandDatas = new Dictionary<Point3, CommandData>();

		private Dictionary<Point3, Chartlet[]> m_chartlets = new Dictionary<Point3, Chartlet[]>();

		private PrimitivesRenderer3D m_primitivesRenderer = new PrimitivesRenderer3D();

		private TexturedBatch3D[] m_batchesByType = new TexturedBatch3D[4];

		private TexturedBatch3D[] m_batchesByType2 = new TexturedBatch3D[4];

		public SubsystemSky m_subsystemSky;

		public SubsystemTerrain m_subsystemTerrain;

		public Action<CommandData> OnCommandBlockGenerated;

		public static int[] m_drawOrders = new int[1] { 110 };

		public int[] DrawOrders => m_drawOrders;

		public override void Load(ValuesDictionary valuesDictionary)
		{
			CommandEditWidget.ScrollPosition.Clear();
			foreach (ValuesDictionary value in valuesDictionary.GetValue<ValuesDictionary>("Commands").Values)
			{
				Point3 position = value.GetValue<Point3>("Position");
				string line = value.GetValue("Line", "");
				SetCommandData(position, line);
			}
			m_subsystemSky = base.Project.FindSubsystem<SubsystemSky>(true);
			m_subsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>(true);
			m_batchesByType[0] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp0"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType[1] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp0"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType[2] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp0"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType[3] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp0"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType2[0] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp1"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType2[1] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp2"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType2[2] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp3"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
			m_batchesByType2[3] = m_primitivesRenderer.TexturedBatch(ContentManager.Get<Texture2D>("Textures/Csharp4"), false, 0, DepthStencilState.DepthRead, RasterizerState.CullCounterClockwiseScissor, BlendState.AlphaBlend, SamplerState.LinearClamp);
		}

		public override void Save(ValuesDictionary valuesDictionary)
		{
			int num = 0;
			ValuesDictionary vd = new ValuesDictionary();
			valuesDictionary.SetValue("Commands", vd);
			foreach (CommandData commandData in m_commandDatas.Values)
			{
				ValuesDictionary vd2 = new ValuesDictionary();
				vd2.SetValue("Position", commandData.Position);
				vd2.SetValue("Line", commandData.Line);
				vd.SetValue(num.ToString(CultureInfo.InvariantCulture), vd2);
				num++;
			}
		}

		public override void Dispose()
		{
			OnCommandBlockGenerated = null;
			try
			{
				CommandConfManager.SaveWhenDispose();
				InstructionManager.SaveHistoryItems();
			}
			catch (Exception e)
			{
				Log.Warning("CommandBlockBehaviorDispose:" + e.Message);
			}
		}

		public override bool OnInteract(TerrainRaycastResult raycastResult, ComponentMiner componentMiner)
		{
			if (!SubsystemCommand.InteractEnable) return false;
			AudioManager.PlaySound("Audio/UI/ButtonClick", 1f, 0f, 0f);
			Point3 position = new Point3(raycastResult.CellFace.X, raycastResult.CellFace.Y, raycastResult.CellFace.Z);
			if (componentMiner.ComponentPlayer != null)
			{
				componentMiner.ComponentPlayer.ComponentGui.ModalPanelWidget = new CommandEditWidget(this.Project, componentMiner.ComponentPlayer, position);
				return true;
			}
			return false;
		}

		public override void OnBlockModified(int value, int oldValue, int x, int y, int z)
		{
			Point3 position = new Point3(x, y, z);
			if (m_chartlets.TryGetValue(position, out Chartlet[] fourChartlet))
			{
				foreach (Chartlet chartlet in fourChartlet)
				{
					int? colorValue = 命令方块.GetColor(Terrain.ExtractData(value));
					chartlet.Color = colorValue.HasValue ? DataHandle.GetCommandColor(colorValue.Value) : Color.Green;
					chartlet.WorkingMode = 命令方块.GetWorkingMode(value);
				}
			}
		}

		public override void OnBlockGenerated(int value, int x, int y, int z, bool isLoaded)
		{
			Point3 position = new Point3(x, y, z);
			CommandData commandData = GetCommandData(position);
			if (commandData == null)
			{
				commandData = SetCommandData(position, "");
			}
			if (OnCommandBlockGenerated != null)
			{
				OnCommandBlockGenerated.Invoke(commandData);
			}
			int? colorValue = 命令方块.GetColor(Terrain.ExtractData(value));
			Color color = colorValue.HasValue ? DataHandle.GetCommandColor(colorValue.Value) : Color.Green;
			Chartlet[] fourChartlet = new Chartlet[4];
			for (int i = 0; i < fourChartlet.Length; i++)
			{
				Chartlet chartlet = new Chartlet();
				Vector3 vector = Vector3.Cross(CellFace.FaceToVector3(i), Vector3.UnitY);
				chartlet.Position = new Vector3(position) + new Vector3(0.5f) + 0.5075f * CellFace.FaceToVector3(i);
				chartlet.P1 = chartlet.Position - 0.52f * (vector + Vector3.UnitY);
				chartlet.P2 = chartlet.Position + 0.52f * (vector - Vector3.UnitY);
				chartlet.P3 = chartlet.Position + 0.52f * (vector + Vector3.UnitY);
				chartlet.P4 = chartlet.Position - 0.52f * (vector - Vector3.UnitY);
				chartlet.Color = color;
				chartlet.WorkingMode = 命令方块.GetWorkingMode(value);
				fourChartlet[i] = chartlet;
			}
			m_chartlets[position] = fourChartlet;
		}

		public override void OnBlockAdded(int value, int oldValue, int x, int y, int z)
		{
			OnBlockGenerated(value, x, y, z, false);
		}

		public override void OnBlockRemoved(int value, int newValue, int x, int y, int z)
		{
			Point3 position = new Point3(x, y, z);
			m_commandDatas.Remove(position);
			m_chartlets.Remove(position);
		}

		public CommandData GetCommandData(Point3 position)
		{
			if (m_commandDatas.TryGetValue(position, out CommandData value))
			{
				return value;
			}
			return null;
		}

		public CommandData SetCommandData(Point3 position, string line)
		{
			CommandData commandData = new(position, line);
			string result = commandData.TrySetValue();
			if (commandData.Name == null)
			{
				commandData.Line = string.Empty;
			}
			//else
			//{
			//	if (InstructionManager.GetInstruction(commandData.Name, false) == null)
			//	{
			//		if (InstructionManager.GetInstruction(commandData.Name, true) == null)
			//		{
			//			commandData.Line = string.Empty;
			//		}
			//	}
			//}
			base.Project.FindSubsystem<SubsystemCommand>(true).ShowEditedTips(result);
			m_commandDatas[position] = commandData;
			return commandData;
		}

		public void Draw(Camera camera, int drawOrder)
		{
			if (!SubsystemCommand.ChartletDraw) return;
			foreach (Point3 point3 in m_chartlets.Keys)
			{
				for (int i = 0; i < m_chartlets[point3].Length; i++)
				{
					Chartlet chartlet = m_chartlets[point3][i];
					if (chartlet.Color.A > 0)
					{
						Vector3 vector = chartlet.Position - camera.ViewPosition;
						float num = Vector3.Dot(vector, camera.ViewDirection);
						Vector3 v = 0.03f * num / vector.Length() * vector;
						if (num > 0.01f && vector.Length() < m_subsystemSky.ViewFogRange.Y)
						{
							if (chartlet.WorkingMode != WorkingMode.变量)
							{
								m_batchesByType[i].QueueQuad(chartlet.P1 - v, chartlet.P2 - v, chartlet.P3 - v, chartlet.P4 - v, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), chartlet.Color);
							}
							else
							{
								m_batchesByType2[i].QueueQuad(chartlet.P1 - v, chartlet.P2 - v, chartlet.P3 - v, chartlet.P4 - v, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), chartlet.Color);
							}
						}
					}
				}
			}
			m_primitivesRenderer.Flush(camera.ViewProjectionMatrix);
		}
	}

	//命令辅助棒行为
	public class SubsystemCmdRodBlockBehavior : SubsystemBlockBehavior, IDrawable, IUpdateable
	{
		public class CommandPointData
		{
			public string Pos;

			public string Value;

			public bool Lock;

			public BevelledButtonWidget Button;
		}

		public override int[] HandledBlocks => new int[1] { 命令辅助棒.Index };

		public SubsystemTerrain m_subsystemTerrain;

		public SubsystemPickables m_subsystemPickables;

		public SubsystemProjectiles m_subsystemProjectiles;

		public SubsystemCommand m_subsystemCommand;

		public SubsystemTime m_subsystemTime;

		public PrimitivesRenderer3D m_primitivesRenderer3D = new PrimitivesRenderer3D();

		public PrimitivesRenderer3D m_primitivesRenderer3D2 = new PrimitivesRenderer3D();

		public Point3? m_recordPosition;

		public int? m_recordBlockValue;

		public Point2? m_recordEyes;

		public int? m_recordfurnitureId;

		public int? m_recordclothesId;

		public string m_recordEntityName = null;

		public string m_commandLine = string.Empty;

		private Color m_color = Color.Yellow;

		private float m_lastGameTime;

		private float m_aimTime;

		private bool m_firstAim = true;

		private Vector3 m_targetPos;

		private Texture2D m_texture;

		private Color m_sightColor;

		public static bool QuickMode = false;

		public int m_pointIndex;

		public StackPanelWidget m_pointDataWidget;

		public BitmapButtonWidget m_withdrawButton;

		public BitmapButtonWidget m_recoveryButton;

		public Dictionary<string, CommandPointData> m_commandPoints = new Dictionary<string, CommandPointData>();

		public static bool ShowRay = true;

		public static bool ShowChunk = false;

		public int[] DrawOrders => new int[1] { 200 };

		public UpdateOrder UpdateOrder => UpdateOrder.Default;

		public void Draw(Camera camera, int drawOrder)
		{
			if (m_subsystemCommand.m_componentPlayer == null) return;
			if (m_targetPos != Vector3.Zero)
			{
				float s = 2f;
				Vector3 playerPos = m_subsystemCommand.m_componentPlayer.ComponentCreatureModel.EyePosition;
				Vector3 direction = Vector3.Normalize(m_targetPos - playerPos);
				Vector3 v = playerPos + direction * 50f;
				var vector = Vector3.Normalize(Vector3.Cross(direction, Vector3.UnitY));
				var v2 = Vector3.Normalize(Vector3.Cross(direction, vector));
				Vector3 p = v + s * (-vector - v2);
				Vector3 p2 = v + s * (vector - v2);
				Vector3 p3 = v + s * (vector + v2);
				Vector3 p4 = v + s * (-vector + v2);
				TexturedBatch3D texturedBatch3D = m_primitivesRenderer3D.TexturedBatch(m_texture, useAlphaTest: false, 0, DepthStencilState.None);
				int count = texturedBatch3D.TriangleVertices.Count;
				texturedBatch3D.QueueQuad(p, p2, p3, p4, new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f), m_sightColor);
				texturedBatch3D.TransformTriangles(camera.ViewMatrix, count);
				m_primitivesRenderer3D.Flush(camera.ProjectionMatrix);
			}
			else
			{
				m_primitivesRenderer3D.Clear();
			}
			if (m_recordPosition.HasValue)
			{
				Vector3 v = new Vector3(m_recordPosition.Value);
				FlatBatch3D flatBatch3D = m_primitivesRenderer3D2.FlatBatch();
				BoundingBox boundingBox = new BoundingBox(v, v + new Vector3(1f));
				Color color = Color.Green;
				if (ShowRay)
				{
					flatBatch3D.QueueLine(v + new Vector3(-100.5f, 0.5f, 0.5f), v + new Vector3(100.5f, 0.5f, 0.5f), Color.Yellow);
					flatBatch3D.QueueLine(v + new Vector3(0.5f, -100.5f, 0.5f), v + new Vector3(0.5f, 100.5f, 0.5f), color);
					flatBatch3D.QueueLine(v + new Vector3(0.5f, 0.5f, -100.5f), v + new Vector3(0.5f, 0.5f, 100.5f), color);
				}
				flatBatch3D.QueueBoundingBox(boundingBox, color);
				flatBatch3D.QueueLine(v + new Vector3(1f, 0, 0), v + new Vector3(0.9f, 0, 0.05f), Color.Yellow);
				flatBatch3D.QueueLine(v + new Vector3(1f, 0, 0), v + new Vector3(0.9f, 0, -0.05f), Color.Yellow);
				flatBatch3D.QueueLine(v + new Vector3(0f, 1f, 0), v + new Vector3(0.05f, 0.9f, 0), color);
				flatBatch3D.QueueLine(v + new Vector3(0f, 1f, 0), v + new Vector3(-0.05f, 0.9f, 0), color);
				flatBatch3D.QueueLine(v + new Vector3(0f, 0, 1f), v + new Vector3(0.05f, 0, 0.9f), color);
				flatBatch3D.QueueLine(v + new Vector3(0f, 0, 1f), v + new Vector3(-0.05f, 0, 0.9f), color);
				if (ShowChunk)
				{
					Color color2 = Color.Blue;
					Point2 coord = Terrain.ToChunk(new Vector2(v.X, v.Z));
					Vector3 origin = new Vector3(coord.X * 16, 0, coord.Y * 16);
					flatBatch3D.QueueLine(origin, origin + new Vector3(0, 255, 0), color2);
					flatBatch3D.QueueLine(origin + new Vector3(0, 0, 16), origin + new Vector3(0, 255, 16), color2);
					flatBatch3D.QueueLine(origin + new Vector3(16, 0, 0), origin + new Vector3(16, 255, 0), color2);
					flatBatch3D.QueueLine(origin + new Vector3(16, 0, 16), origin + new Vector3(16, 255, 16), color2);
				}
				m_primitivesRenderer3D2.Flush(camera.ViewProjectionMatrix);
			}
			else
			{
				m_primitivesRenderer3D2.Clear();
			}
		}

		public override bool OnAim(Ray3 aim, ComponentMiner componentMiner, AimState state)
		{
			if (m_firstAim)
			{
				m_lastGameTime = (float)m_subsystemTime.GameTime;
				m_aimTime = 0;
				m_firstAim = false;
				m_targetPos = Vector3.Zero;
				m_sightColor = Color.Red;
			}
			if (state == AimState.InProgress)
			{
				m_aimTime = (float)m_subsystemTime.GameTime - m_lastGameTime;
				if (m_aimTime > 1f)
				{
					object result = DataHandle.Raycast(aim, componentMiner);
					if (result is TerrainRaycastResult)
					{
						CellFace cellFace = ((TerrainRaycastResult)result).CellFace;
						m_targetPos = new Vector3(cellFace.Point) + new Vector3(0.5f) - aim.Direction * 2f;
						m_sightColor = Color.Green;
					}
					else if (result is BodyRaycastResult)
					{
						ComponentBody componentBody = ((BodyRaycastResult)result).ComponentBody;
						m_targetPos = componentBody.Position - aim.Direction * 2f;
						m_sightColor = Color.Green;
					}
					else if (result is Ray3)
					{
						Ray3 ray = (Ray3)result;
						m_targetPos = ray.Position + ray.Direction * 100;
						m_sightColor = Color.Red;
					}
				}
			}
			else if (state == AimState.Completed)
			{
				m_firstAim = true;
				if (m_sightColor != Color.Red)
				{
					componentMiner.ComponentPlayer.ComponentBody.Position = m_targetPos;
					m_targetPos = Vector3.Zero;
					m_sightColor = Color.Red;
					return true;
				}
				else
				{
					m_targetPos = Vector3.Zero;
				}
			}
			else if (state == AimState.Cancelled)
			{
				m_firstAim = true;
				m_targetPos = Vector3.Zero;
			}
			return false;
		}

		public override bool OnUse(Ray3 ray, ComponentMiner componentMiner)
		{
			object result = componentMiner.Raycast(ray, RaycastMode.Digging);
			Point2 playerEyes = DataHandle.GetPlayerEyesAngle(componentMiner.ComponentPlayer);
			//Point2 cameraEyes = DataHandle.DirectionToEyes(componentMiner.ComponentPlayer.PlayerData.GameWidget.ActiveCamera.ViewDirection);
			string eyesDebug = string.Format("\n视角: 水平方向:{0},垂直方向:{1}", playerEyes.X, playerEyes.Y);
			if (result is TerrainRaycastResult)
			{
				CellFace cellFace = ((TerrainRaycastResult)result).CellFace;
				int cellValue = m_subsystemTerrain.Terrain.GetCellValue(cellFace.X, cellFace.Y, cellFace.Z);
				int limitValue = Terrain.ReplaceLight(cellValue, 0);
				int id = Terrain.ExtractContents(cellValue);
				int data = Terrain.ExtractData(cellValue);
				int dropsValue = -1;
				foreach (Pickable pickable in m_subsystemPickables.Pickables)
				{
					float distance = Vector3.Distance(pickable.Position, new Vector3(cellFace.Point));
					if (distance <= 1.5f)
					{
						dropsValue = pickable.Value;
						break;
					}
				}
				string blockDebug = string.Empty;
				string furnitureDebug = string.Empty;
				string dropsDebug = string.Empty;
				blockDebug = string.Format("方块ID:{0}；特殊值:{1}；方块值:{2}\n标准坐标:({3},{4},{5})；方块面:{6}", id, data, limitValue, cellFace.X, cellFace.Y, cellFace.Z, cellFace.Face);
				if (id == 命令方块.Index)
				{
					componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(blockDebug, Color.LightBlue, false, false);
					return false;
				}
				if (id == 227)
				{
					int furnitureIndex = FurnitureBlock.GetDesignIndex(data);
					int furnitureRotation = FurnitureBlock.GetRotation(data);
					int furnitureFace = ((cellFace.Face - furnitureRotation) >= 0) ? (cellFace.Face - furnitureRotation) : (cellFace.Face - furnitureRotation + 4);
					if (cellFace.Face == 4 || cellFace.Face == 5)
					{
						furnitureFace = cellFace.Face;
					}
					m_recordfurnitureId = furnitureIndex;
					furnitureDebug = string.Format("\n家具序号:{0}；家具面:{1}", furnitureIndex, furnitureFace);
				}
				if (dropsValue != -1)
				{
					int dropsId = Terrain.ExtractContents(dropsValue);
					int dropsData = Terrain.ExtractData(dropsValue);
					dropsDebug = string.Format("\n检测到掉落物的ID:{0}；特殊值:{1}；方块值:{2}", dropsId, dropsData, dropsValue);
					if (dropsId == 203)
					{
						int clothId = ClothingBlock.GetClothingIndex(dropsData);
						m_recordclothesId = clothId;
						dropsDebug += "；衣物序号:" + clothId;
					}
				}
				SetPointData(cellFace.Point);
				m_recordPosition = cellFace.Point;
				m_recordBlockValue = (dropsValue != -1) ? dropsValue : limitValue;
				m_recordEyes = playerEyes;
				componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(blockDebug + eyesDebug + furnitureDebug + dropsDebug, m_color, false, false);
				return true;
			}
			else if (result is BodyRaycastResult)
			{
				ComponentBody componentBody = ((BodyRaycastResult)result).ComponentBody;
				if (componentBody != null)
				{
					string keyName = componentBody.Entity.ValuesDictionary.DatabaseObject.Name.ToLower();
					ComponentCreature componentCreature = componentBody.Entity.FindComponent<ComponentCreature>();
					ComponentDamage componentDamage = componentBody.Entity.FindComponent<ComponentDamage>();
					string entityDebug = "生物实体名:" + keyName;
					Point3 bodyPos = DataHandle.GetBodyPoint(componentBody);
					if (componentCreature != null)
					{
						string displayName = componentCreature.DisplayName;
						float health = componentCreature.ComponentHealth.Health * 100;
						string mass = componentBody.Mass.ToString();
						string boxSize = componentBody.BoxSize.ToString();
						float flySpeed = componentCreature.ComponentLocomotion.FlySpeed;
						float walkSpeed = componentCreature.ComponentLocomotion.WalkSpeed;
						float jumpSpeed = componentCreature.ComponentLocomotion.JumpSpeed;
						componentCreature.ComponentLocomotion.SwimSpeed.ToString();
						entityDebug += string.Format("；名称:{0}；\n血量:{1}%；质量:{2}；\n位置:({3})；碰撞箱:{4}；", displayName, health, mass, bodyPos.ToString(), boxSize);
						entityDebug += string.Format("\n飞行速度:{0}；行走速度:{1}；跳跃速度:{2}", MathF.Round(flySpeed * 10f) / 10f, MathF.Round(walkSpeed * 10f) / 10f, MathF.Round(jumpSpeed * 10f) / 10f);
					}
					else if (componentDamage != null)
					{
						float hitPoint = componentDamage.Hitpoints * 100;
						float attackRes = componentDamage.AttackResilience;
						string mass = componentBody.Mass.ToString();
						string boxSize = componentBody.BoxSize.ToString();
						entityDebug += string.Format("；血量:{0}%；\n攻击抗性:{1}；质量:{2}；\n位置:({3})；碰撞箱:{4}；", hitPoint, attackRes, mass, bodyPos.ToString(), boxSize);
					}
					SetPointData(bodyPos);
					m_recordPosition = bodyPos;
					m_recordEntityName = keyName;
					componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(entityDebug, m_color, false, false);
					return true;
				}
			}
			else if (result is MovingBlocksRaycastResult)
			{
				IMovingBlockSet movingBlockSet = ((MovingBlocksRaycastResult)result).MovingBlockSet;
				string moveDebug = (movingBlockSet.Tag != null) ? "该运动方块标签名为:" + movingBlockSet.Tag.ToString() : "该运动方块标签名不存在";
				moveDebug += "；所在位置:" + string.Format("({0})", movingBlockSet.Position.ToString());
				SetPointData(new Point3(movingBlockSet.Position));
				m_recordPosition = new Point3(movingBlockSet.Position);
				componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(moveDebug, m_color, false, false);
				return true;
			}
			else
			{
				Point3 playerPos = DataHandle.GetBodyPoint(componentMiner.ComponentPlayer.ComponentBody);
				SetPointData(playerPos);
				m_recordPosition = playerPos;
				m_recordEntityName = "player";
				m_recordEyes = playerEyes;
				componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(string.Format("玩家名:player; 玩家坐标:({0})", playerPos.ToString()) + eyesDebug, m_color, false, false);
			}
			return false;
		}

		public override bool OnEditInventoryItem(IInventory inventory, int slotIndex, ComponentPlayer componentPlayer)
		{
			if (componentPlayer.ComponentGui.ModalPanelWidget is CommandEditWidget)
			{
				CommandEditWidget commandEditWidget = (CommandEditWidget)componentPlayer.ComponentGui.ModalPanelWidget;
				commandEditWidget.ParentWidget.ClearChildren();
				CommandEditWidget.GuiWidgetControl(componentPlayer, true);
				componentPlayer.ComponentGui.ModalPanelWidget = null;
			}
			else
			{
				componentPlayer.ComponentGui.ModalPanelWidget = new CommandEditWidget(base.Project, componentPlayer, Point3.Zero, true);
			}
			return true;
		}

		public override void Load(ValuesDictionary valuesDictionary)
		{
			m_subsystemTerrain = base.Project.FindSubsystem<SubsystemTerrain>(true);
			m_subsystemPickables = base.Project.FindSubsystem<SubsystemPickables>(true);
			m_subsystemProjectiles = base.Project.FindSubsystem<SubsystemProjectiles>(true);
			m_subsystemCommand = base.Project.FindSubsystem<SubsystemCommand>(true);
			m_subsystemTime = base.Project.FindSubsystem<SubsystemTime>(true);
			m_texture = ContentManager.Get<Texture2D>("Textures/Gui/Sights");
			m_commandLine = valuesDictionary.GetValue<string>("CommandLine");
			m_pointIndex = 0;
		}

		public override void Save(ValuesDictionary valuesDictionary)
		{
			valuesDictionary.SetValue("CommandLine", m_commandLine);
		}

		public void Update(float dt)
		{
			//if (QuickMode && !HasCollidabled)
			//{
			//    CollidableBlocks = new bool[BlocksManager.Blocks.Length];
			//    for (int b = 0; b < BlocksManager.Blocks.Length; b++)
			//    {
			//        CollidableBlocks[b] = BlocksManager.Blocks[b].IsCollidable;
			//        BlocksManager.Blocks[b].IsCollidable = false;
			//    }
			//    HasCollidabled = true;
			//}
			//if (!QuickMode && HasCollidabled)
			//{
			//    for (int b = 0; b < CollidableBlocks.Length; b++)
			//    {
			//        BlocksManager.Blocks[b].IsCollidable = CollidableBlocks[b];
			//    }
			//    HasCollidabled = false;
			//}
			if (m_pointDataWidget == null && !string.IsNullOrEmpty(m_commandLine))
			{
				InitPointDataWidget();
			}
			if (m_subsystemCommand.m_componentPlayer != null)
			{
				m_subsystemCommand.m_componentPlayer.ComponentBody.TerrainCollidable = !QuickMode;
			}
			if (m_pointDataWidget != null && m_subsystemCommand.m_componentPlayer != null)
			{
				Vector2 vector = m_subsystemCommand.m_componentPlayer.GameWidget.ActualSize;
				m_subsystemCommand.m_componentPlayer.GameWidget.SetWidgetPosition(m_withdrawButton, new Vector2(vector.X - 180, 23));
				m_subsystemCommand.m_componentPlayer.GameWidget.SetWidgetPosition(m_recoveryButton, new Vector2(vector.X - 130, 23));
				bool isActiveRodBlock = (Terrain.ExtractContents(m_subsystemCommand.m_componentPlayer.ComponentMiner.ActiveBlockValue) == 命令辅助棒.Index);
				bool isActiveCommandWidget = m_subsystemCommand.m_componentPlayer.ComponentGui.ModalPanelWidget is CommandEditWidget;
				m_pointDataWidget.IsVisible = (QuickMode && isActiveRodBlock && !isActiveCommandWidget);
				m_withdrawButton.IsVisible = m_pointDataWidget.IsVisible;
				m_recoveryButton.IsVisible = m_pointDataWidget.IsVisible;
				if (m_pointDataWidget.IsVisible)
				{
					if (m_withdrawButton.IsClicked)
					{
						if (WithdrawBlockManager.WithdrawMode)
						{
							WithdrawBlockManager.CarryOut(Project.FindSubsystem<SubsystemCommandDef>());
						}
						else
						{
							m_subsystemCommand.m_componentPlayer.ComponentGui.DisplaySmallMessage("请开启撤回模式", m_color, false, false);
						}
					}
					if (m_recoveryButton.IsClicked)
					{
						if (WithdrawBlockManager.WithdrawMode)
						{
							WithdrawBlockManager.Recovery(Project.FindSubsystem<SubsystemCommandDef>());
						}
						else
						{
							m_subsystemCommand.m_componentPlayer.ComponentGui.DisplaySmallMessage("请开启撤回模式", m_color, false, false);
						}
					}
					foreach (string p in m_commandPoints.Keys)
					{
						if (m_commandPoints[p].Button.IsClicked)
						{
							m_commandPoints[p].Lock = !m_commandPoints[p].Lock;
							SetPointColor(p);
							string tips = p.Replace("pos", "点") + (m_commandPoints[p].Lock ? "已锁定" : "已解锁");
							m_subsystemCommand.m_componentPlayer.ComponentGui.DisplaySmallMessage(tips, Color.Yellow, false, false);
						}
					}
				}
			}
		}

		public void InitPointDataWidget()
		{
			if (m_pointDataWidget == null)
			{
				m_withdrawButton = new BitmapButtonWidget();
				m_withdrawButton.IsVisible = false;
				m_withdrawButton.Size = new Vector2(40, 40);
				m_withdrawButton.NormalSubtexture = new Subtexture(ContentManager.Get<Texture2D>("Textures/Withdraw1"), Vector2.Zero, Vector2.One);
				m_withdrawButton.ClickedSubtexture = new Subtexture(ContentManager.Get<Texture2D>("Textures/Withdraw2"), Vector2.Zero, Vector2.One);
				m_subsystemCommand.m_componentPlayer.GameWidget.Children.Add(m_withdrawButton);
				m_recoveryButton = new BitmapButtonWidget();
				m_recoveryButton.IsVisible = false;
				m_recoveryButton.Size = new Vector2(40, 40);
				m_recoveryButton.NormalSubtexture = new Subtexture(ContentManager.Get<Texture2D>("Textures/Withdraw3"), Vector2.Zero, Vector2.One);
				m_recoveryButton.ClickedSubtexture = new Subtexture(ContentManager.Get<Texture2D>("Textures/Withdraw4"), Vector2.Zero, Vector2.One);
				m_subsystemCommand.m_componentPlayer.GameWidget.Children.Add(m_recoveryButton);
				m_pointDataWidget = new StackPanelWidget();
				m_pointDataWidget.Name = "PointDataWidget";
				m_pointDataWidget.Direction = LayoutDirection.Vertical;
				m_subsystemCommand.m_componentPlayer.GameWidget.SetWidgetPosition(m_pointDataWidget, new Vector2(100, 20));
				m_pointDataWidget.IsHitTestVisible = false;
				m_pointDataWidget.ClampToBounds = true;
				m_pointDataWidget.IsVisible = false;
				m_subsystemCommand.m_componentPlayer.GameWidget.Children.Add(m_pointDataWidget);
			}
			m_pointDataWidget.Children.Clear();
			m_commandPoints.Clear();
			string[] kws = m_commandLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string k in kws)
			{
				if (k.StartsWith("pos"))
				{
					string[] sp = k.Split(new char[] { ':' });
					if (sp[0] == "pos") sp[0] = "pos1";
					CommandPointData pointData = new CommandPointData();
					pointData.Pos = sp[0];
					pointData.Value = sp[1];
					pointData.Lock = false;
					m_commandPoints[pointData.Pos] = pointData;
				}
			}
			if (m_commandPoints.Count > 0)
			{
				if (m_pointIndex >= m_commandPoints.Count) m_pointIndex = m_commandPoints.Count - 1;
				foreach (string p in m_commandPoints.Keys)
				{
					BevelledButtonWidget buttonWidget = new BevelledButtonWidget();
					m_commandPoints[p].Button = buttonWidget;
					buttonWidget.Name = p;
					buttonWidget.Text = p.Replace("pos", "点") + ":" + m_commandPoints[p].Value;
					buttonWidget.Size = new Vector2(200, 50);
					buttonWidget.CenterColor = new Color(64, 64, 64, 32);
					buttonWidget.BevelSize = 0.7f;
					SetPointColor(p);
					m_pointDataWidget.Children.Add(buttonWidget);
					CanvasWidget canvasWidget = new CanvasWidget();
					canvasWidget.Size = new Vector2(0, 5);
					m_pointDataWidget.Children.Add(canvasWidget);
				}
				SetPointSize();
			}
		}

		public void SetPointData(Point3 point)
		{
			try
			{
				if (!QuickMode || m_commandPoints.Count == 0 || string.IsNullOrEmpty(m_commandLine)) return;
				if (m_recordPosition.HasValue && point == m_recordPosition)
				{
					Time.QueueTimeDelayedExecution(Time.RealTime + 0.1f, delegate
					{
						CommandData commandData = new CommandData(Point3.Zero, m_commandLine);
						commandData.TrySetValue();
						m_subsystemCommand.Submit(commandData.Name, commandData, false);
						m_subsystemCommand.m_componentPlayer.ComponentGui.DisplaySmallMessage(string.Format("已提交指令:{0}${1}", commandData.Name, commandData.Type), Color.Yellow, false, false);
					});
				}
				else
				{
					if (m_pointIndex >= m_commandPoints.Count) m_pointIndex = m_commandPoints.Count - 1;
					foreach (string pk in m_commandPoints.Keys)
					{
						m_commandPoints[pk].Button.Color = m_commandPoints[pk].Lock ? Color.Red : Color.White;
						m_commandPoints[pk].Button.BevelColor = m_commandPoints[pk].Button.Color;
					}
					bool LockAll = true;
					foreach (string pk in m_commandPoints.Keys)
					{
						if (!m_commandPoints[pk].Lock)
						{
							LockAll = false;
							break;
						}
					}
					if (LockAll) return;
					do
					{
						m_pointIndex = (m_pointIndex + 1) % m_commandPoints.Count;
					}
					while (m_commandPoints["pos" + (m_pointIndex + 1)].Lock);
					string p = "pos" + (m_pointIndex + 1);
					if (m_commandPoints.Count == 1)
					{
						m_commandLine = m_commandLine.Replace("pos:" + m_commandPoints[p].Value, "pos:" + point.ToString());
					}
					else
					{
						m_commandLine = m_commandLine.Replace(p + ":" + m_commandPoints[p].Value, p + ":" + point.ToString());
					}
					m_commandPoints[p].Value = point.ToString();
					m_commandPoints[p].Button.Text = p.Replace("pos", "点") + ":" + point.ToString();
					SetPointSize();
					SetPointColor(p);
				}
			}
			catch (Exception e)
			{
				Log.Warning("DebugPoint:" + e.Message);
			}
		}

		public void SetPointColor(string p)
		{
			m_commandPoints[p].Button.Color = (p == "pos" + (m_pointIndex + 1)) ? Color.Green : Color.White;
			if (m_commandPoints[p].Lock) m_commandPoints[p].Button.Color = Color.Red;
			m_commandPoints[p].Button.BevelColor = m_commandPoints[p].Button.Color;
		}

		public void SetPointSize()
		{
			int maxSize = 0;
			foreach (string pk in m_commandPoints.Keys)
			{
				if (maxSize < m_commandPoints[pk].Button.Text.Length) maxSize = m_commandPoints[pk].Button.Text.Length;
			}
			foreach (string pk in m_commandPoints.Keys)
			{
				m_commandPoints[pk].Button.Size = new Vector2(maxSize * 13.3f, 50);
			}
		}
	}

	//指令对象
	public class Instruction
	{
		public string Name;//指令名称

		public string About;//指令速览

		public bool Condition;//是否为条件判断

		public bool Survival; //是否为生存可用

		public List<string> Types = new List<string>();//命令类型

		public Dictionary<string, string> Demos = new Dictionary<string, string>();//key:type value:指令演示

		public Dictionary<string, string> Details = new Dictionary<string, string>();//key:type value:指令说明

		public Dictionary<string, string[]> Paras = new Dictionary<string, string[]>();//key:type value:所有变量

		public Dictionary<string, string> Definitions = new Dictionary<string, string>();//key:type$v value:变量说明

		public Dictionary<string, Point2> Ranges = new Dictionary<string, Point2>();//key:type$v value:变量范围

		public Dictionary<string, string> Options = new Dictionary<string, string>();//key:type$v value:变量选项
	}

	//屏幕贴图对象
	public class ScreenPattern
	{
		public string Name;

		public string Texture;

		public Widget Widget;

		public int Layer;

		public float OutTime;
	}

	//排序方块对象
	public class Order
	{
		public Block block;

		public int order;

		public int value;

		public Order(Block b, int o, int v)
		{
			block = b;
			order = o;
			value = v;
		}
	}

	//录制对象
	public class RecordPlayerStats
	{
		public float Time;

		public Vector3 Position;

		public Quaternion Rotation;

		public Vector2 LookAngles;

		public int ActiveBlockValue;

		public bool Flying;

		public bool Walking;

		public bool Sneaking;
	}

	//录制管理
	public class RecordManager
	{
		public class RecordPlayerAction
		{
			public string ActionName;

			public float ActionTime;

			public Point3 Point;

			public int Value;

			public void MakeAction(ComponentPlayer componentPlayer)
			{
				componentPlayer.m_subsystemTerrain.DestroyCell(0, Point.X, Point.Y, Point.Z, Value, noDrop: true, noParticleSystem: false);
				componentPlayer.m_subsystemAudio.PlaySound("Audio/BlockPlaced", 1f, 0f, new Vector3(Point.X, Point.Y, Point.Z), 5f, autoDelay: false);
				componentPlayer.Entity.FindComponent<ComponentHumanModel>().m_handAngles2 = new Vector2(-0.2f, 0.3f);
			}
		}

		public static Dictionary<Point3, int> ChangeBlocks = new Dictionary<Point3, int>();

		public static List<RecordPlayerStats> RecordPlayerStats = new List<RecordPlayerStats>();

		public static List<RecordPlayerAction> RecordPlayerActions = new List<RecordPlayerAction>();

		public static bool Recording = false;

		public static bool Replaying = false;

		public static float FrameTime = 0.01f;

		public static int StatsIndex = 0;

		public static int ActionIndex = 0;

		public static Vector3 FirstPosition;

		public static Vector3 FirstDirection;

		public static float FirstTime;

		public static float ReplayTime;

		public static void Replay(ComponentPlayer componentPlayer, float dt)
		{
			ReplayTime += dt;
			if (StatsIndex >= RecordPlayerStats.Count)
			{
				Replaying = false;
				componentPlayer.GameWidget.ActiveCamera = componentPlayer.GameWidget.FindCamera<FppCamera>(true);
			}
			RecordPlayerStats record = RecordPlayerStats[StatsIndex];
			if (record.Time - FirstTime - ReplayTime <= 0.02f)
			{
				componentPlayer.ComponentBody.Position = record.Position;
				componentPlayer.ComponentBody.Rotation = record.Rotation;
				componentPlayer.ComponentLocomotion.LookAngles = record.LookAngles;
				int slot = componentPlayer.ComponentMiner.Inventory.ActiveSlotIndex;
				int count = componentPlayer.ComponentMiner.Inventory.GetSlotCount(slot);
				componentPlayer.ComponentMiner.Inventory.RemoveSlotItems(slot, count);
				componentPlayer.ComponentMiner.Inventory.AddSlotItems(slot, record.ActiveBlockValue, count);
				componentPlayer.ComponentLocomotion.m_flying = record.Flying;
				componentPlayer.ComponentLocomotion.m_walking = record.Walking;
				componentPlayer.ComponentBody.IsSneaking = record.Sneaking;
				StatsIndex++;
			}
			while (ActionIndex < RecordPlayerActions.Count)
			{
				float time = RecordPlayerActions[ActionIndex].ActionTime - FirstTime - ReplayTime;
				if (time <= 0.02f)
				{
					RecordPlayerActions[ActionIndex].MakeAction(componentPlayer);
					ActionIndex++;
				}
				else break;
			}
		}

		public static void AddRecordPlayerStats(ComponentPlayer componentPlayer, float time)
		{
			RecordPlayerStats record = new RecordPlayerStats();
			record.Time = time;
			record.Position = componentPlayer.ComponentBody.Position;
			record.Rotation = componentPlayer.ComponentBody.Rotation;
			record.LookAngles = componentPlayer.ComponentLocomotion.LookAngles;
			record.ActiveBlockValue = componentPlayer.ComponentMiner.ActiveBlockValue;
			record.Flying = componentPlayer.ComponentLocomotion.m_flying;
			record.Walking = componentPlayer.ComponentLocomotion.m_walking;
			record.Sneaking = componentPlayer.ComponentBody.IsSneaking;
			RecordPlayerStats.Add(record);
		}
	}

	//编辑历史记录项
	public class HistoryEditItem
	{
		public string About;

		public string Line;

		public Point3 Position;

		public bool Pass;

		public bool Condition;

		public bool Collection;
	}

	//指令管理 
	public class InstructionManager
	{
		public static Dictionary<string, Instruction> FunInstructions = new Dictionary<string, Instruction>();//key=name

		public static Dictionary<string, Instruction> ConInstructions = new Dictionary<string, Instruction>();//key=if:name

		public static List<HistoryEditItem> HistoryEditInstructions = new List<HistoryEditItem>();

		public static List<HistoryEditItem> CollectionInstructions = new List<HistoryEditItem>();

		public static void Initialize()
		{
			foreach (ContentInfo contentInfo in ContentManager.List())
			{
				if (contentInfo.Filename.StartsWith("InstructionsDoc"))
				{
					string text = string.Empty;
					try
					{
						text = ContentManager.Get<string>(contentInfo.Filename.Split(new char[] { '.' })[0]);
					}
					catch
					{
					}
					if (!string.IsNullOrEmpty(text))
					{
						string[] classify = text.Split(new char[1] { '#' });
						if (classify != null && classify.Length > 8)
						{
							SetInstructions(classify[2], classify[4], false);
							SetInstructions(classify[6], classify[8], true);
						}
					}
				}
			}
			LoadHistoryItems();
			SetMoreOptions();
		}

		public static Instruction GetInstruction(string name, bool iscon)
		{
			if (!iscon)
			{
				if (FunInstructions.TryGetValue(name, out Instruction value))
				{
					return value;
				}
			}
			else
			{
				if (ConInstructions.TryGetValue("if:" + name, out Instruction value))
				{
					return value;
				}
			}
			Log.Error("InstructionManager:找不到" + name + "指令的定义");
			return null;
		}

		public static string GetDisplayName(string name)
		{
			if (!name.Contains(":")) name = "cmd:" + name;
			return name.Split(new char[1] { ':' })[1];
		}

		public static string GetCommandType(string name, bool iscon, string type)
		{
			Instruction instruction = GetInstruction(name, iscon);
			if (instruction != null && instruction.Types.Contains(type)) return type;
			return "default";
		}

		public static string GetInstructionDemo(string name, string type, bool iscon)
		{
			Instruction instruction = GetInstruction(name, iscon);
			if (instruction != null && instruction.Demos.TryGetValue(type, out string value))
			{
				return value;
			}
			return string.Empty;
		}

		public static string GetInstructionDetail(string name, string type, bool iscon)
		{
			Instruction instruction = GetInstruction(name, iscon);
			if (instruction != null && instruction.Details.TryGetValue(type, out string value))
			{
				Regex regex = new Regex(@"\((.+)\)");
				string definition = regex.Match(value).Value;
				if (!string.IsNullOrEmpty(definition))
				{
					return value.Replace(definition, "");
				}
				else
				{
					return value;
				}
			}
			return "暂无";
		}

		public static string[] GetInstructionOption(string name, string type, string para, bool iscon)
		{
			Instruction instruction = GetInstruction(name, iscon);
			if (instruction != null && instruction.Options.TryGetValue(type + "$" + para, out string value))
			{
				return value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			}
			return null;
		}

		public static string GetParameterName(string name, string type, string para, bool iscon)
		{
			Instruction instruction = GetInstruction(name, iscon);
			if (instruction != null)
			{
				foreach (var v in instruction.Definitions)
				{
					if (type + "$" + para == v.Key) return v.Value;
				}
				if (para.StartsWith("text")) return "文本信息" + para.Replace("text", "");
				else if (para.StartsWith("color")) return "颜色" + para.Replace("color", "");
				else if (para.StartsWith("pos")) return "坐标" + para.Replace("pos", "");
				else if (para.StartsWith("eyes")) return "视角" + para.Replace("eyes", "");
				else if (para.StartsWith("id")) return "方块值" + para.Replace("id", "");
				else if (para.StartsWith("fid")) return "家具序号" + para.Replace("fid", "");
				else if (para.StartsWith("cid")) return "衣物序号" + para.Replace("cid", "");
				else if (para.StartsWith("obj")) return "生物对象" + para.Replace("obj", "");
				else if (para.StartsWith("con")) return "开闭" + para.Replace("con", "");
				else return "请输入值";
			}
			return "未知属性";
		}

		public static bool IsFixedParameter(string para)
		{
			return (para == "cmd" || para == "if" || para == "type" || para == "cd");
		}

		public static bool IsInvalidOption(string value, string name, string type, string para, bool iscon)
		{
			string[] options = GetInstructionOption(name, type, para, iscon);
			if (options != null)
			{
				foreach (string option in options)
				{
					if (option.Contains(":"))
					{
						if (value == option.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries)[0].Replace(" ", ""))
						{
							return true;
						}
					}
					else
					{
						if (value == option)
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		public static Dictionary<string, Instruction> GetSurvivalList(Dictionary<string, Instruction> instructions)
		{
			Dictionary<string, Instruction> surInstructions = [];
			foreach (string key in instructions.Keys)
			{
				if (instructions[key].Survival)
				{
					surInstructions.Add(key, instructions[key]);
				}
			}
			return surInstructions;
		}

		public static void SetInstructions(string classify1, string classify2, bool iscon)
		{
			Dictionary<string, Instruction> Instructions = iscon ? ConInstructions : FunInstructions;
			string funAbout = classify1.Replace("\n", "#");
			string[] arfunAbout = funAbout.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string line in arfunAbout)
			{
				if (line.StartsWith("//")) continue;
				string[] words = line.Split(new char[1] { '=' }, StringSplitOptions.RemoveEmptyEntries);
				if (words != null && words.Length == 2)
				{
					if (!Instructions.TryGetValue(words[0], out Instruction instruction))
					{
						instruction = new Instruction();
						instruction.Name = words[0];
						instruction.About = words[1].Replace("*", "");
						instruction.Survival = !words[1].Contains("*");
						instruction.Condition = iscon;
						if (!instruction.Condition)
						{
							FunInstructions[instruction.Name] = instruction;
						}
						else
						{
							ConInstructions[instruction.Name] = instruction;
						}
					}
					else
					{
						instruction.Name = words[0];
						instruction.About = words[1].Replace("*", "");
						instruction.Survival = !words[1].Contains("*");
					}
				}
			}

			string funDefinition = classify2.Replace("\n", "#");
			string[] arfunDefinition = funDefinition.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string line in arfunDefinition)
			{
				if (line.StartsWith("//")) continue;
				string[] words = line.Split(new char[1] { '=' }, StringSplitOptions.RemoveEmptyEntries);
				if (words != null && words.Length >= 2)
				{
					string[] word = words[0].Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
					if (!Instructions.TryGetValue(word[0], out Instruction instruction))
					{
						instruction = new Instruction();
						instruction.Name = word[0];
						instruction.About = "暂无相关说明";
						instruction.Condition = iscon;
						instruction.Survival = true;
						if (!instruction.Condition)
						{
							FunInstructions[instruction.Name] = instruction;
						}
						else
						{
							ConInstructions[instruction.Name] = instruction;
						}
					}
					string type = word[1].Split(new char[1] { ':' })[1];
					instruction.Types.Add(type);
					instruction.Demos.Add(type, words[0]);
					instruction.Details.Add(type, words[1]);
					string[] paras = new string[word.Length - 2];
					for (int i = 0; i < word.Length - 2; i++)
					{
						paras[i] = word[i + 2].Split(new char[1] { ':' })[0];
					}
					instruction.Paras.Add(type, paras);
					Regex regex = new Regex(@"\((.+)\)");
					string defparas = regex.Match(words[1]).Value;
					if (!string.IsNullOrEmpty(defparas))
					{
						defparas = defparas.Substring(1, defparas.Length - 2);
						string[] defpara = defparas.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string def in defpara)
						{
							Point2 valueRange = Point2.Zero;
							string deftemp = def;
							Regex regex2 = new Regex(@"\[(.+)\]");
							string defrange = regex2.Match(def).Value;
							if (!string.IsNullOrEmpty(defrange))
							{
								deftemp = deftemp.Replace(defrange, "");
								defrange = defrange.Substring(1, defrange.Length - 2);
								string[] range = defrange.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
								if (range.Length == 2)
								{
									valueRange = new Point2(int.Parse(range[0]), int.Parse(range[1]));
								}
							}
							string[] ardeftemp = deftemp.Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries);
							if (ardeftemp.Length == 2)
							{
								string type_v = type + "$" + ardeftemp[0];
								instruction.Definitions.Add(type_v, ardeftemp[1]);
								if (valueRange != Point2.Zero)
								{
									instruction.Ranges.Add(type_v, valueRange);
								}
							}
						}
					}
					if (words.Length > 2)
					{
						string temp = words[2].Replace("\r", "");
						string[] parasOptions = temp.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
						foreach (string paraOption in parasOptions)
						{
							string[] arParaOption = paraOption.Split(new char[1] { '@' }, StringSplitOptions.RemoveEmptyEntries);
							string type_v = type + "$" + arParaOption[0];
							instruction.Options.Add(type_v, arParaOption[1]);
						}
					}
				}
			}
		}

		public static void AddHistoryItem(HistoryEditItem historyEditItem)
		{
			if (historyEditItem == null) return;
			if (HistoryEditInstructions.Count > 0)
			{
				HistoryEditItem lastHistoryEditItem = HistoryEditInstructions[HistoryEditInstructions.Count - 1];
				if (lastHistoryEditItem.Line == historyEditItem.Line && lastHistoryEditItem.Collection == historyEditItem.Collection)
				{
					HistoryEditInstructions[HistoryEditInstructions.Count - 1] = historyEditItem;
				}
				else
				{
					HistoryEditInstructions.Add(historyEditItem);
				}
			}
			else
			{
				HistoryEditInstructions.Add(historyEditItem);
			}
			if (historyEditItem.Collection)
			{
				foreach (var h in CollectionInstructions)
				{
					if (h.Line == historyEditItem.Line)
					{
						CollectionInstructions.Remove(h);
						break;
					}
				}
				CollectionInstructions.Add(historyEditItem);
			}
		}

		public static void RemoveHistoryItem(HistoryEditItem historyEditItem)
		{
			if (historyEditItem == null) return;
			if (CollectionInstructions.Contains(historyEditItem))
			{
				CollectionInstructions.Remove(historyEditItem);
			}
			if (HistoryEditInstructions.Contains(historyEditItem))
			{
				HistoryEditInstructions.Remove(historyEditItem);
			}
		}

		public static void LoadHistoryItems()
		{
			string historyItemPath = Storage.CombinePaths(DataHandle.GetCommandPath(), "HistoryEditItems.txt");
			Stream stream = Storage.OpenFile(historyItemPath, OpenFileMode.CreateOrOpen);
			StreamReader streamReader = new StreamReader(stream);
			string line = string.Empty;
			while ((line = streamReader.ReadLine()) != null)
			{
				string[] stritems = line.Split(new char[1] { '#' }, StringSplitOptions.RemoveEmptyEntries);
				if (stritems.Length >= 6)
				{
					HistoryEditItem historyEditItem = new HistoryEditItem();
					historyEditItem.About = stritems[0];
					historyEditItem.Line = stritems[1];
					historyEditItem.Position = DataHandle.GetPoint3Value(stritems[2]);
					historyEditItem.Pass = (stritems[3] == "True");
					historyEditItem.Condition = (stritems[4] == "True");
					historyEditItem.Collection = (stritems[5] == "True");
					AddHistoryItem(historyEditItem);
				}
			}
			stream.Dispose();
		}

		public static void SaveHistoryItems()
		{
			string historyItemPath = Storage.CombinePaths(DataHandle.GetCommandPath(), "HistoryEditItems.txt");
			Stream stream = Storage.OpenFile(historyItemPath, OpenFileMode.Create);
			using (StreamWriter streamWriter = new StreamWriter(stream))
			{
				foreach (HistoryEditItem item in HistoryEditInstructions)
				{
					string line = string.Format("{0}#{1}#{2}#{3}#{4}#{5}", item.About.Replace("\r", ""), item.Line, item.Position.ToString(), item.Pass.ToString(), item.Condition.ToString(), item.Collection.ToString());
					streamWriter.WriteLine(line);
				}
				streamWriter.Flush();
			}
			stream.Dispose();
		}

		public static void SetMoreOptions()
		{
			Instruction instruction = GetInstruction("texture", false);
			if (instruction != null)
			{
				string line = string.Empty;
				foreach (EntityInfo entityInfo in EntityInfoManager.EntityInfos.Values)
				{
					if (entityInfo.KeyName == "boat") continue;
					line += entityInfo.Texture.Replace("Textures/Creatures/", "") + ":" + entityInfo.DisplayName + ",";
				}
				instruction.Options.Add("pakcreature$opt", line);
			}
			Instruction instruction2 = GetInstruction("audio", false);
			if (instruction2 != null)
			{
				string line = string.Empty;
				foreach (ContentInfo contentInfo in ContentManager.List())
				{
					if (contentInfo.ContentPath.StartsWith("Audio/"))
					{
						line += contentInfo.ContentPath.Replace("Audio/", "") + ",";
					}
				}
				instruction2.Options.Add("contentpak$opt", line);
			}
			Instruction instruction3 = GetInstruction("model", false);
			if (instruction3 != null)
			{
				string line = string.Empty;
				foreach (ContentInfo contentInfo in ContentManager.List())
				{
					if (contentInfo.ContentPath.StartsWith("Models/"))
					{
						line += contentInfo.ContentPath.Replace("Models/", "") + ",";
					}
				}
				instruction3.Options.Add("pakmodel$opt", line);
			}
		}
	}

	//配置资源管理
	public class CommandConfManager
	{
		public static bool Initialize()
		{
			string commandPath = DataHandle.GetCommandPath();
			string confPath = Storage.CombinePaths(commandPath, "Settings.xml");
			if (Storage.FileExists(confPath))
			{
				Stream stream = Storage.OpenFile(confPath, OpenFileMode.Read);
				try
				{
					XElement xSettings = XmlUtils.LoadXmlFromStream(stream, Encoding.UTF8, true);
					stream.Dispose();
					foreach (XElement x in xSettings.Elements("Settings").ToList())
					{
						switch (x.Attribute("Name").Value)
						{
							case "WithdrawMode": WithdrawBlockManager.WithdrawMode = x.Value.Contains("True"); break;
							case "WithdrawSteps": WithdrawBlockManager.MaxSteps = int.Parse(x.Value); break;
							case "ShowRay": SubsystemCmdRodBlockBehavior.ShowRay = x.Value.Contains("True"); break;
						}
					}
				}
				catch
				{
					stream.Dispose();
					Log.Warning("Load Settings Fail");
				}
			}
			else
			{
				SaveWhenDispose();
				foreach (ContentInfo info in ContentManager.List())
				{
					if (info.AbsolutePath.StartsWith("Command/"))
					{
						string commandFile = Storage.GetSystemPath(Storage.CombinePaths(commandPath, info.Filename));
						FileStream fileStream = new FileStream(commandFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
						byte[] buff = new byte[info.ContentStream.Length];
						info.ContentStream.Read(buff, 0, buff.Length);
						fileStream.Write(buff, 0, buff.Length);
						fileStream.Flush();
						fileStream.Dispose();
					}
				}
				return false;
			}
			return true;
		}

		public static void SaveWhenDispose()
		{
			string commandPath = DataHandle.GetCommandPath();
			string confPath = Storage.CombinePaths(commandPath, "Settings.xml");
			Stream stream = Storage.OpenFile(confPath, OpenFileMode.Create);
			try
			{
				XElement xSettings = new XElement("CommandConf");
				AddSaveAttribute(xSettings, "WithdrawMode", WithdrawBlockManager.WithdrawMode.ToString());
				AddSaveAttribute(xSettings, "WithdrawSteps", WithdrawBlockManager.MaxSteps.ToString());
				AddSaveAttribute(xSettings, "ShowRay", SubsystemCmdRodBlockBehavior.ShowRay.ToString());
				XmlUtils.SaveXmlToStream(xSettings, stream, Encoding.UTF8, true);
				stream.Dispose();
			}
			catch
			{
				stream.Dispose();
				Log.Warning("Save Settings Fail");
			}
		}

		public static void AddSaveAttribute(XElement xSettings, string name, string value)
		{
			XElement xtopic = new XElement("Settings");
			XmlUtils.SetAttributeValue(xtopic, "Name", name);
			xtopic.Value = value;
			xSettings.Add(xtopic);
		}
	}

	//生物实体信息
	public class EntityInfo
	{
		public string KeyName = string.Empty;

		public string EntityName = string.Empty;

		public string DisplayName = string.Empty;

		public string Model = string.Empty;

		public string Texture = string.Empty;
	}

	//实体信息管理
	public class EntityInfoManager
	{
		public static string[][] ModelTypes = new string[][]
		{
			 new string[] { "Body", "Head", "Leg1", "Leg2", "Hand1", "Hand2" }, //人模型
			 new string[] { "Body", "#Neck", "Head", "Leg1", "Leg2", "Leg3", "Leg4" }, //四脚动物模型，#表示可为空
			 new string[] { "Body", "Neck", "Head", "Leg1", "Leg2", "#Wing1", "#Wing2" }, //鸟模型
			 new string[] { "Body", "#Neck", "Head", "Leg1", "Leg2" }, //不飞鸟模型
			 new string[] { "Body",  "Tail1", "Tail2", "#Jaw" }, //鱼模型
		};

		public static Dictionary<string, EntityInfo> EntityInfos = new Dictionary<string, EntityInfo>();

		public static EntityInfo GetEntityInfo(string name)
		{
			if (EntityInfos.TryGetValue(name, out EntityInfo modelInfo))
			{
				return modelInfo;
			}
			return null;
		}

		public static void SetEntityInfos()
		{
			var playerEntityInfo = new EntityInfo
			{
				KeyName = "player",
				EntityName = "MalePlayer",
				DisplayName = "玩家",
				Model = "Models/HumanMale",
				Texture = "Textures/Creatures/HumanMale1",
			};
			var boatEntityInfo = new EntityInfo
			{
				KeyName = "boat",
				EntityName = "Boat",
				DisplayName = "船",
				Model = "Models/Boat",
				Texture = "Textures/Boat",
			};
			EntityInfos.Add(playerEntityInfo.KeyName, playerEntityInfo);
			EntityInfos.Add(boatEntityInfo.KeyName, boatEntityInfo);
			foreach (ValuesDictionary entitiesValuesDictionary in DatabaseManager.EntitiesValuesDictionaries)
			{
				try
				{
					string name = entitiesValuesDictionary.DatabaseObject.Name.ToLower();
					if (name == "maleplayer" || name == "femaleplayer") continue;
					ValuesDictionary valuesDictionary = DatabaseManager.FindValuesDictionaryForComponent(entitiesValuesDictionary, typeof(ComponentCreature));
					if (valuesDictionary != null)
					{
						string value = valuesDictionary.GetValue<string>("DisplayName");
						if (value.StartsWith("[") && value.EndsWith("]"))
						{
							string[] lp = value.Substring(1, value.Length - 2).Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
							value = LanguageControl.GetDatabase("DisplayName", lp[1]);
						}
						if (!string.IsNullOrEmpty(value))
						{
							ValuesDictionary valuesDictionary2 = DatabaseManager.FindValuesDictionaryForComponent(entitiesValuesDictionary, typeof(ComponentCreatureModel));
							var modelInfo = new EntityInfo
							{
								KeyName = entitiesValuesDictionary.DatabaseObject.Name.ToLower(),
								EntityName = entitiesValuesDictionary.DatabaseObject.Name,
								DisplayName = value,
								Model = valuesDictionary2.GetValue<string>("ModelName"),
								Texture = valuesDictionary2.GetValue<string>("TextureOverride"),
							};
							EntityInfos.Add(modelInfo.KeyName, modelInfo);
						}
					}
				}
				catch
				{
				}
			}
			foreach (ValuesDictionary entitiesValuesDictionary in DatabaseManager.EntitiesValuesDictionaries)
			{
				try
				{
					if (entitiesValuesDictionary.DatabaseObject.Name == "Boat") continue;
					ValuesDictionary valuesDictionary = DatabaseManager.FindValuesDictionaryForComponent(entitiesValuesDictionary, typeof(ComponentDamage));
					if (valuesDictionary != null)
					{
						ValuesDictionary valuesDictionary2 = DatabaseManager.FindValuesDictionaryForComponent(entitiesValuesDictionary, typeof(ComponentModel));
						if (valuesDictionary2 != null)
						{
							var modelInfo = new EntityInfo
							{
								KeyName = entitiesValuesDictionary.DatabaseObject.Name.ToLower(),
								EntityName = entitiesValuesDictionary.DatabaseObject.Name,
								DisplayName = entitiesValuesDictionary.DatabaseObject.Name,
								Model = valuesDictionary2.GetValue<string>("ModelName"),
								Texture = valuesDictionary2.GetValue<string>("TextureOverride"),
							};
							EntityInfos.Add(modelInfo.KeyName, modelInfo);
						}
					}
				}
				catch
				{
				}
			}
		}

		public static string GetModelType(Model model)
		{
			List<string> meshs = new List<string>();
			foreach (ModelMesh modelMesh in model.Meshes)
			{
				meshs.Add(modelMesh.Name);
			}
			for (int i = 0; i < ModelTypes.Length; i++)
			{
				bool isSame = true;
				foreach (string mesh in ModelTypes[i])
				{
					if (mesh.StartsWith("#")) continue;
					if (!meshs.Contains(mesh))
					{
						isSame = false;
						break;
					}
				}
				if (isSame)
				{
					switch (i)
					{
						case 0: return "HumanModel";
						case 1: return "FourLeggedModel";
						case 2: return "BirdModel";
						case 3: return "FlightlessBirdModel";
						case 4: return "FishModel";
					}
				}
			}
			return "OtherModel";
		}

		public static string GetModelType(string obj)
		{
			Entity entity = DatabaseManager.CreateEntity(GameManager.Project, GetEntityName(obj), true);
			ComponentModel componentModel = entity.FindComponent<ComponentModel>();
			if (componentModel != null)
			{
				return componentModel.GetType().Name.Replace("Component", "");
			}
			return "OtherModel";
		}

		public static string GetModelTypeDisplayName(string modelName)
		{
			switch (modelName)
			{
				case "HumanModel": return "人模型";
				case "FourLeggedModel": return "四脚动物模型";
				case "BirdModel": return "鸟模型";
				case "FlightlessBirdModel": return "不飞鸟模型";
				case "FishModel": return "鱼模型";
			}
			return "其他模型";
		}

		public static string GetEntityName(string obj)
		{
			EntityInfo modelInfo = GetEntityInfo(obj);
			return (modelInfo != null) ? modelInfo.EntityName : obj;
		}

		public static void ChangeModelDisplay(ref ModelWidget modelWidget, string model, string texture)
		{
			modelWidget.Model = ContentManager.Get<Model>(model);
			modelWidget.TextureOverride = ContentManager.Get<Texture2D>(texture);
			var absoluteTransforms = new Matrix[modelWidget.Model.Bones.Count];
			modelWidget.Model.CopyAbsoluteBoneTransformsTo(absoluteTransforms);
			BoundingBox boundingBox = modelWidget.Model.CalculateAbsoluteBoundingBox(absoluteTransforms);
			float x = MathUtils.Max(boundingBox.Size().X, 1.4f * boundingBox.Size().Y, boundingBox.Size().Z);
			modelWidget.ViewPosition = new Vector3(boundingBox.Center().X, 1.5f, boundingBox.Center().Z) + 2.6f * MathF.Pow(x, 0.75f) * new Vector3(-1f, 0f, -1f);
			modelWidget.ViewTarget = boundingBox.Center();
			modelWidget.ViewFov = 0.3f;
			modelWidget.AutoRotationVector = Vector3.Zero;
			float n = Math.Clamp(boundingBox.Size().XZ.Length() / boundingBox.Size().Y, 1f, 1.5f);
			modelWidget.Size = new Vector2(modelWidget.Size.Y * n, modelWidget.Size.Y);
		}
	}

	//贴图对象
	public class Pattern
	{
		public Point3 Point;

		public Vector3 Position;

		public Texture2D Texture;

		public string TexName;

		public Vector3 Right;

		public Vector3 Up;

		public Color Color;

		public float Size;

		public float LWratio;
	}

	//文字贴图对象
	public class PatternFont
	{
		public Point3 Point;

		public Vector3 Position;

		public string Text;

		public Vector3 Right;

		public Vector3 Down;

		public Color Color;

		public float Size;
	}

	//音乐对象
	public class CommandMusic(string name, Sound sound)
	{
		public string Name = name;
		public Sound Sound = sound;

		public static float GetRealPitch(int p, ref int o)
		{
			if (p <= 11)
			{
				return GetPitch(p);
			}
			else
			{
				o = o + 1;
				return GetPitch(p - 11);
			}
		}

		public static float GetPitch(int p)
		{
			if (p > 11) return 1f;
			float pitch = 1f;
			float num = 0f;
			float num2 = 130.8125f * MathF.Pow(1.05946314f, p);
			int num3 = 0;
			for (int i = 4; i <= 6; i++)
			{
				float num4 = num2 / (523.25f * MathF.Pow(2f, i - 5));
				if (num3 == 0 || (num4 >= 0.5f && num4 < num))
				{
					num3 = i;
					num = num4;
				}
			}
			if (num != 0)
			{
				pitch = Math.Clamp(MathF.Log(num) / MathF.Log(2f), -1f, 1f);
			}
			return MathF.Pow(2f, pitch);
		}
	}

	//运动方块标识对象
	public class MovingBlockTag
	{
		public string Name;

		public CoordDirection Face;

		public Point3 Axis;
	}

	//运动实体方块对象
	public class MovingEntityBlock
	{
		public int Id;

		public Point3 Offset;

		public string Data;
	}

	//运动碰撞对象
	public class MovingCollision
	{
		public int Block = 0;

		public string Creature = string.Empty;
	}

	//自定义闪电粒子
	public class LightningStrikeParticleSystem : ParticleSystem<LightningStrikeParticleSystem.Particle>
	{
		public class Particle : Game.Particle
		{
			public float TimeToLive;
			public Color ShowColor;
		}

		public PrimitivesRenderer3D m_primitivesRenderer3D = new PrimitivesRenderer3D();

		public Random m_random = new Random();

		public LightningStrikeParticleSystem(Vector3 position, Color color)
			: base(1)
		{
			Particle obj = base.Particles[0];
			obj.IsActive = true;
			obj.Position = position;
			obj.TimeToLive = 1f;
			obj.ShowColor = color;
		}

		public override bool Simulate(float dt)
		{
			dt = Math.Clamp(dt, 0f, 0.1f);
			bool flag = false;
			for (int i = 0; i < base.Particles.Length; i++)
			{
				Particle particle = base.Particles[i];
				if (particle.IsActive)
				{
					flag = true;
					particle.TimeToLive -= dt;
					if (particle.TimeToLive <= 0f)
					{
						particle.IsActive = false;
					}
				}
			}
			return !flag;
		}

		public override void Draw(Camera camera)
		{
			FlatBatch3D flatBatch3D = m_primitivesRenderer3D.FlatBatch(0, DepthStencilState.DepthRead, null, BlendState.Additive);
			Vector3 unitY = Vector3.UnitY;
			Vector3 v = Vector3.Normalize(Vector3.Cross(camera.ViewDirection, unitY));
			Viewport viewport = Display.Viewport;
			for (int c = 0; c < base.Particles.Length; c++)
			{
				Particle particle = base.Particles[c];
				if (particle.IsActive)
				{
					Vector3 value = particle.Position;
					float num = Vector4.Transform(new Vector4(value, 1f), camera.ViewProjectionMatrix).W * 2f / (viewport.Width * camera.ProjectionMatrix.M11);
					for (int i = 0; i < (int)(particle.TimeToLive * 30f); i++)
					{
						float s = m_random.NormalFloat(0f, 1f * num);
						float s2 = m_random.NormalFloat(0f, 1f * num);
						Vector3 v2 = s * v + s2 * unitY;
						float num2 = 260f;
						while (num2 > value.Y)
						{
							uint num3 = MathUtils.Hash((uint)(particle.Position.X + 100f * particle.Position.Z + 200f * num2));
							float num4 = MathUtils.Lerp(4f, 10f, (float)(double)(num3 & 0xFF) / 255f);
							float s3 = ((num3 & 1) == 0) ? 1 : (-1);
							float s4 = MathUtils.Lerp(0.05f, 0.2f, (float)(double)((num3 >> 8) & 0xFF) / 255f);
							float num5 = num2;
							float num6 = num5 - num4 * MathUtils.Lerp(0.45f, 0.55f, (float)(double)((num3 >> 16) & 0xFF) / 255f);
							float num7 = num5 - num4 * MathUtils.Lerp(0.45f, 0.55f, (float)(double)((num3 >> 24) & 0xFF) / 255f);
							float num8 = num5 - num4;
							Vector3 p = new Vector3(value.X, num5, value.Z) + v2;
							Vector3 vector = new Vector3(value.X, num6, value.Z) + v2 - num4 * v * s3 * s4;
							Vector3 vector2 = new Vector3(value.X, num7, value.Z) + v2 + num4 * v * s3 * s4;
							Vector3 p2 = new Vector3(value.X, num8, value.Z) + v2;
							Color color = particle.ShowColor;
							flatBatch3D.QueueLine(p, vector, color, color);
							flatBatch3D.QueueLine(vector, vector2, color, color);
							flatBatch3D.QueueLine(vector2, p2, color, color);
							num2 -= num4;
						}
					}
				}
			}
			m_primitivesRenderer3D.Flush(camera.ViewProjectionMatrix);
		}
	}

	//自定义相机
	public class CommandCamera : BasePerspectiveCamera
	{
		public enum CameraType
		{
			Lock, Aero, MovePos, MoveDirect, MoveWithPlayer
		}

		public Vector3 m_position;

		public Vector3 m_direction;

		public Vector3 m_targetPosition;

		public Vector3 m_targetDirection;

		public Vector3 m_relativePosition;

		public Point2 m_relativeAngle;

		public CameraType m_type;

		public float m_speed;

		public bool m_skipToAero;

		private Vector3 m_velocity;

		private bool m_usesMovementControls;

		private bool m_isEntityControlEnabled;

		public override bool UsesMovementControls => m_usesMovementControls;

		public override bool IsEntityControlEnabled => m_isEntityControlEnabled;

		public CommandCamera(GameWidget gameWidget, CameraType type)
			: base(gameWidget)
		{
			m_type = type;
			m_velocity = Vector3.Zero;
			m_targetPosition = Vector3.Zero;
			m_targetDirection = Vector3.Zero;
			m_relativePosition = Vector3.Zero;
			m_relativeAngle = Point2.Zero;
			m_speed = 0;
			m_skipToAero = false;
			switch (m_type)
			{
				case CameraType.Aero: m_usesMovementControls = true; m_isEntityControlEnabled = true; break;
				case CameraType.Lock: m_usesMovementControls = false; m_isEntityControlEnabled = true; break;
				case CameraType.MoveDirect: m_usesMovementControls = false; m_isEntityControlEnabled = false; break;
				case CameraType.MovePos: m_usesMovementControls = false; m_isEntityControlEnabled = false; break;
				case CameraType.MoveWithPlayer: m_usesMovementControls = false; m_isEntityControlEnabled = true; break;
				default: break;
			}
		}

		public override void Activate(Camera previousCamera)
		{
			m_position = previousCamera.ViewPosition;
			m_direction = previousCamera.ViewDirection;
			SetupPerspectiveCamera(m_position, m_direction, Vector3.UnitY);
		}

		public override void Update(float dt)
		{
			if (m_type == CameraType.Aero)
			{
				Vector3 vector = Vector3.Zero;
				Vector2 vector2 = Vector2.Zero;
				ComponentInput componentInput = base.GameWidget.PlayerData.ComponentPlayer?.ComponentInput;
				if (componentInput != null)
				{
					vector = componentInput.PlayerInput.CameraMove * new Vector3(1f, 0f, 1f);
					vector2 = componentInput.PlayerInput.CameraLook;
				}
				Vector3 direction = m_direction;
				Vector3 unitY = Vector3.UnitY;
				Vector3 vector3 = Vector3.Normalize(Vector3.Cross(direction, unitY));
				float num = 10f;
				Vector3 zero = Vector3.Zero;
				zero += num * vector.X * vector3;
				zero += num * vector.Y * unitY;
				zero += num * vector.Z * direction;
				m_velocity += 1.5f * (zero - m_velocity) * dt;
				if (MathF.Abs(vector.X) < 0.01f && MathF.Abs(vector.Z) < 0.01f)
				{
					m_velocity = new Vector3(0, 0, 0);
				}
				m_position += m_velocity * dt;
				m_direction = Vector3.Transform(m_direction, Matrix.CreateFromAxisAngle(unitY, -4f * vector2.X * dt));
				m_direction = Vector3.Transform(m_direction, Matrix.CreateFromAxisAngle(vector3, 4f * vector2.Y * dt));
				Vector3 up = Vector3.TransformNormal(Vector3.UnitY, Matrix.CreateFromAxisAngle(m_direction, 0f));
				SetupPerspectiveCamera(m_position, m_direction, up);
			}
			else if (m_type == CameraType.Lock)
			{
				SetupPerspectiveCamera(m_position, m_direction, Vector3.UnitY);
			}
			else if (m_type == CameraType.MovePos)
			{
				float x = Vector3.Distance(m_targetPosition, m_position);
				if (x != 0)
				{
					m_position += MathF.Min(dt * m_speed, x) * Vector3.Normalize(m_targetPosition - m_position);
				}
				else
				{
					if (m_skipToAero)
					{
						m_type = CameraType.Aero;
						m_usesMovementControls = true;
						m_isEntityControlEnabled = true;
					}
				}
				SetupPerspectiveCamera(m_position, m_direction, Vector3.UnitY);
			}
			else if (m_type == CameraType.MoveDirect)
			{
				float x = Vector3.Dot(m_targetDirection, m_direction) / m_targetDirection.Length() * m_direction.Length();
				if (x < 1)
				{
					m_direction = m_direction + Vector3.Normalize(m_targetDirection - m_direction) * dt * m_speed * 0.1f;
				}
				else
				{
					if (m_skipToAero)
					{
						m_type = CameraType.Aero;
						m_usesMovementControls = true;
						m_isEntityControlEnabled = true;
					}
				}
				SetupPerspectiveCamera(m_position, m_direction, Vector3.UnitY);
			}
			else if (m_type == CameraType.MoveWithPlayer)
			{
				ComponentPlayer componentPlayer = base.GameWidget.PlayerData.ComponentPlayer;
				Vector3 playerBodyDirect = DataHandle.GetPlayerBodyDirection(componentPlayer);
				Vector3 v1 = Vector3.Normalize(new Vector3(playerBodyDirect.X, 0, playerBodyDirect.Z)) * m_relativePosition.X;
				Vector3 v2 = new Vector3(0, 1, 0) * m_relativePosition.Y;
				Vector3 v3 = Vector3.Normalize(new Vector3(-playerBodyDirect.Z, 0, playerBodyDirect.X)) * m_relativePosition.Z;
				m_position = componentPlayer.ComponentBody.Position + v1 + v2 + v3;
				m_direction = DataHandle.EyesToDirection(DataHandle.EyesAdd(DataHandle.GetPlayerEyesAngle(componentPlayer), m_relativeAngle));
				SetupPerspectiveCamera(m_position, m_direction, Vector3.UnitY);
			}
		}
	}

	//玩家相关组件
	public class ComponentPostprocessing : Component
	{
		public ComponentPlayer m_componentPlayer;

		//UpdateOrder IUpdateable.UpdateOrder => UpdateOrder.FirstPersonModels;

		public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
		{
			m_componentPlayer = Entity.FindComponent<ComponentPlayer>();
		}

		public void Update(float dt)
		{
			//if (m_componentPlayer != null && SubsystemCmdRodBlockBehavior.QuickMode)
			//{
			//	if (!m_componentPlayer.ComponentBody.MoveToFreeSpace(float.PositiveInfinity))
			//	{
			//		m_componentPlayer.ComponentHealth.Health = 1f;
			//		m_componentPlayer.ComponentHealth.m_redScreenFactor = 0f;
			//		m_componentPlayer.ComponentBody.Position += new Vector3(0, 1f, 0);
			//	}
			//}
		}
	}

	//撤回方块管理
	public class WithdrawBlockManager
	{
		public class Cell
		{
			public Point3 Point;
			public int Value;
		}
		public class WithdrawEntity
		{
			public List<Cell> WithdrawCellList = new List<Cell>();
			public Point3 MinPoint;
			public Point3 MaxPoint;
		}

		public static bool WithdrawMode = true;

		public static int Index = -1;

		public static int MaxSteps = 10;

		public static string WorldDirectoryName;

		public static Dictionary<int, WithdrawEntity> WithdrawEntitys = new Dictionary<int, WithdrawEntity>();

		public static Dictionary<int, CommandData> RecoveryEntitys = new Dictionary<int, CommandData>();

		public DynamicArray<Cell> CurrentCells = new DynamicArray<Cell>();

		public void SetCurrentCell(int x, int y, int z, int oldValue, int value)
		{
			if (oldValue != value)
			{
				CurrentCells.Add(new Cell
				{
					Point = new Point3(x, y, z),
					Value = oldValue
				});
			}
		}

		public void SetWithdrawEntity(Point3 minPoint, Point3 maxPoint)
		{
			WithdrawEntitys[Index] = new WithdrawEntity();
			WithdrawEntitys[Index].MinPoint = minPoint;
			WithdrawEntitys[Index].MaxPoint = maxPoint;
			WithdrawEntitys[Index].WithdrawCellList = CurrentCells.ToList();
		}

		public void SetRecoveryEntity(CommandData commandData)
		{
			RecoveryEntitys[Index] = new CommandData(commandData.Position, commandData.Line);
			RecoveryEntitys[Index].TrySetValue();
		}

		public void UpdateWithdrawCell(CommandData commandData, Point3 minPoint, Point3 maxPoint)
		{
			if (!WithdrawMode || CurrentCells.Count == 0) return;
			if (WithdrawEntitys.Count < MaxSteps)
			{
				Index = WithdrawEntitys.Count;
				SetWithdrawEntity(minPoint, maxPoint);
				SetRecoveryEntity(commandData);
			}
			else
			{
				for (int i = 0; i < MaxSteps - 1; i++)
				{
					WithdrawEntitys[i] = WithdrawEntitys[i + 1];
					RecoveryEntitys[i] = RecoveryEntitys[i + 1];
				}
				Index = MaxSteps - 1;
				SetWithdrawEntity(minPoint, maxPoint);
				SetRecoveryEntity(commandData);
			}
			CurrentCells.Clear();

		}

		public static void Recovery(SubsystemCommandDef subsystemCommandDef)
		{
			if (RecoveryEntitys.TryGetValue(Index + 1, out CommandData value) && value != null)
			{
				subsystemCommandDef.Project.FindSubsystem<SubsystemCommand>().Submit(value.Name, value, false);
				subsystemCommandDef.ShowSubmitTips("重做完成:" + value.Name + "$" + value.Type);
			}
			else
			{
				subsystemCommandDef.ShowSubmitTips("没有可重做步骤");
			}
		}

		public static void CarryOut(SubsystemCommandDef subsystemCommandDef)
		{
			if (WithdrawEntitys.TryGetValue(Index, out WithdrawEntity value))
			{
				subsystemCommandDef.ShowSubmitTips("正在撤回上一步，请稍后");
				foreach (var cell in value.WithdrawCellList)
				{
					int oldValue = subsystemCommandDef.m_subsystemTerrain.Terrain.GetCellValueFast(cell.Point.X, cell.Point.Y, cell.Point.Z);
					int oldId = Terrain.ExtractContents(oldValue);
					subsystemCommandDef.m_subsystemTerrain.Terrain.SetCellValueFast(cell.Point.X, cell.Point.Y, cell.Point.Z, cell.Value);
					if (oldId == 27 || oldId == 45 || oldId == 64 || oldId == 216)
					{
						SubsystemBlockBehavior[] blockBehaviors = subsystemCommandDef.m_subsystemTerrain.m_subsystemBlockBehaviors.GetBlockBehaviors(oldId);
						for (int i = 0; i < blockBehaviors.Length; i++)
						{
							blockBehaviors[i].OnBlockRemoved(oldValue, cell.Value, cell.Point.X, cell.Point.Y, cell.Point.Z);
						}
					}
				}
				subsystemCommandDef.UpdateChunks(value.MinPoint, value.MaxPoint);
				WithdrawEntitys.Remove(Index);
				Index--;
				subsystemCommandDef.ShowSubmitTips("撤回完成，剩余可撤回步骤为" + (Index + 1) + "步");
			}
			else
			{
				subsystemCommandDef.ShowSubmitTips("没有记录的可撤回步骤");
			}
		}

		public static void Clear()
		{
			if (GameManager.m_worldInfo != null && GameManager.m_worldInfo.DirectoryName != WorldDirectoryName)
			{
				WithdrawEntitys.Clear();
				Index = -1;
				WorldDirectoryName = GameManager.m_worldInfo.DirectoryName;
			}
		}
	}

	//复制方块管理
	public class CopyBlockManager
	{
		public class CopyBlockData
		{
			public int Value;
			public int Data;
			public int Id;
			public string ExtraData;
			public object DirectData;
		}

		public string WorldDirectoryName;

		public bool HandleFurniture;

		public bool HandleAir;

		public bool HandleExtraData;

		public SubsystemCommandDef SubsystemCommandDef;

		public WithdrawBlockManager WBManager;

		public CubeArea CubeArea;

		public Point3 CopyOrigin;

		public Dictionary<Point3, CopyBlockData> CopyBlockDatas = new Dictionary<Point3, CopyBlockData>();

		public CopyBlockManager(SubsystemCommandDef subsystemCommandDef, WithdrawBlockManager wbManager, Point3 point1, Point3 point2, bool handleFurniture = false, bool handleAir = false, bool handleExtraData = false)
		{
			SubsystemCommandDef = subsystemCommandDef;
			WBManager = wbManager;
			HandleFurniture = handleFurniture;
			HandleAir = handleAir;
			HandleExtraData = handleExtraData;
			WorldDirectoryName = GameManager.m_worldInfo.DirectoryName;
			CubeArea = new CubeArea(point1, point2);
			CubeArea.Ergodic(delegate
			{
				int value = SubsystemCommandDef.m_subsystemTerrain.Terrain.GetCellValue(CubeArea.Current.X, CubeArea.Current.Y, CubeArea.Current.Z);
				CopyBlockData copyData = new CopyBlockData();
				copyData.Value = value;
				copyData.Data = Terrain.ExtractData(value);
				copyData.Id = Terrain.ExtractContents(value);
				if ((!HandleAir && copyData.Id != 0) || HandleAir)
				{
					GetCopyExtraData(copyData, CubeArea.Current);
					CopyBlockDatas[CubeArea.Current] = copyData;
				}
				return false;
			});
		}

		public void ClearBlockArea(bool applyChangeCell = false)
		{
			foreach (var p in CopyBlockDatas.Keys)
			{
				if (!SubsystemCommandDef.m_subsystemTerrain.Terrain.IsCellValid(p.X, p.Y, p.Z)) return;
				int oldId = CopyBlockDatas[p].Id;
				if (WithdrawBlockManager.WithdrawMode && WBManager != null)
				{
					WBManager.SetCurrentCell(p.X, p.Y, p.Z, CopyBlockDatas[p].Value, 0);
				}
				if (oldId == 27 || oldId == 45 || oldId == 64 || oldId == 216)
				{
					ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(p.X, p.Y, p.Z);
					if (blockEntity != null)
					{
						blockEntity.Entity.FindComponent<ComponentInventoryBase>().m_slots.Clear();
					}
					SubsystemCommandDef.m_subsystemTerrain.ChangeCell(p.X, p.Y, p.Z, 0);
				}
				else if (applyChangeCell)
				{
					SubsystemCommandDef.m_subsystemTerrain.ChangeCell(p.X, p.Y, p.Z, 0);
				}
				else
				{
					SubsystemCommandDef.m_subsystemTerrain.Terrain.SetCellValueFast(p.X, p.Y, p.Z, 0);
				}
			}
		}

		public void CopyFromCache(Point3 placePoint)
		{
			if (HandleFurniture && GameManager.m_worldInfo.DirectoryName != WorldDirectoryName)
			{
				SubsystemFurnitureBlockBehavior furnitureBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>();
				int setIndex = 1;
				bool setNameExist;
				string setName;
				do
				{
					setNameExist = false;
					setName = "CommandSet" + setIndex;
					foreach (FurnitureSet set in furnitureBlockBehavior.FurnitureSets)
					{
						if (set.Name == setName)
						{
							setNameExist = true;
							break;
						}
					}
					setIndex++;
				}
				while (setNameExist);
				int max = -1;
				for (int i = 0; i < furnitureBlockBehavior.m_furnitureDesigns.Length; i++)
				{
					if (furnitureBlockBehavior.m_furnitureDesigns[i] != null) max = i;
				}
				List<FurnitureDesign> sortFurnitures = SortFurniture();
				if (sortFurnitures.Count > 0)
				{
					FurnitureSet furnitureSet = furnitureBlockBehavior.NewFurnitureSet(setName, string.Empty);
					foreach (var furniture in sortFurnitures)
					{
						if (furniture != null)
						{
							FurnitureDesign furniture2 = furniture.Clone();
							furniture2.Index = furniture.Index + max;
							furnitureBlockBehavior.m_furnitureDesigns[furniture2.Index] = furniture2;
							furnitureBlockBehavior.AddToFurnitureSet(furniture2, furnitureSet);
						}
					}
				}
				foreach (var p in CopyBlockDatas.Keys)
				{
					if (CopyBlockDatas[p].Id == 227 && CopyBlockDatas[p].DirectData != null)
					{
						FurnitureDesign furniture = (FurnitureDesign)CopyBlockDatas[p].DirectData;
						furniture.Index = furniture.Index + max;
						CopyBlockDatas[p].Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(CopyBlockDatas[p].Data, furniture.Index, furniture.ShadowStrengthFactor, furniture.IsLightEmitter));
					}
				}
			}
			foreach (var p in CopyBlockDatas.Keys)
			{
				Point3 point = placePoint - CopyOrigin + p;
				if (CopyBlockDatas[p].Id != 0)
				{
					ChangeBlockValue(point, CopyBlockDatas[p]);
				}
			}
		}

		public void DirectCopy(Point3 placePoint, bool applyAir)
		{
			foreach (var p in CopyBlockDatas.Keys)
			{
				Point3 point = placePoint - CopyOrigin + p;
				if (!applyAir)
				{
					if (CopyBlockDatas[p].Id != 0)
					{
						ChangeBlockValue(point, CopyBlockDatas[p]);
					}
				}
				else
				{
					ChangeBlockValue(point, CopyBlockDatas[p]);
				}
			}
		}

		public void MirrorCopy(Point3 planePoint, string plane, bool laminate)
		{
			foreach (var p in CopyBlockDatas.Keys)
			{
				if (CopyBlockDatas[p].Id != 0)
				{
					SetMirrorValue(CopyBlockDatas[p], plane);
					Point3 point = GetMirrorPoint(p, planePoint, plane, laminate);
					ChangeBlockValue(point, CopyBlockDatas[p]);
				}
			}
		}

		public void RotateCopy(Point3 axisPoint, string axis, string angle, bool applyChangeCell = false)
		{
			foreach (var p in CopyBlockDatas.Keys)
			{
				if (CopyBlockDatas[p].Id != 0)
				{
					SetRotateValue(CopyBlockDatas[p], axis, angle);
					Point3 point = GetRotatePoint(p, axisPoint, axis, angle);
					ChangeBlockValue(point, CopyBlockDatas[p], applyChangeCell);
				}
			}
		}

		public void ChangeBlockValue(Point3 point, CopyBlockData copyData, bool applyChangeCell = false)
		{
			if (!SubsystemCommandDef.m_subsystemTerrain.Terrain.IsCellValid(point.X, point.Y, point.Z)) return;
			int oldValue = SubsystemCommandDef.m_subsystemTerrain.Terrain.GetCellValueFast(point.X, point.Y, point.Z);
			int oldId = Terrain.ExtractContents(oldValue);
			if (WithdrawBlockManager.WithdrawMode && WBManager != null)
			{
				WBManager.SetCurrentCell(point.X, point.Y, point.Z, oldValue, copyData.Value);
			}
			if (oldId == 27 || oldId == 45 || oldId == 64 || oldId == 216)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, 0);
			}
			if (copyData.Id == 27 || copyData.Id == 45 || copyData.Id == 64 || copyData.Id == 216)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
				ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(point.X, point.Y, point.Z);
				if (blockEntity != null)
				{
					ComponentInventoryBase inventoryBase = blockEntity.Entity.FindComponent<ComponentInventoryBase>();
					if (copyData.DirectData != null)
					{
						var slots = (List<ComponentInventoryBase.Slot>)copyData.DirectData;
						if (copyData.Id == 27)
						{
							for (int s = 0; s < slots.Count - 2; s++)
							{
								inventoryBase.AddSlotItems(s, slots[s].Value, slots[s].Count);
							}
						}
						else
						{
							for (int s = 0; s < slots.Count; s++)
							{
								inventoryBase.AddSlotItems(s, slots[s].Value, slots[s].Count);
							}
						}
					}
				}
			}
			else if (copyData.Id == 97 || copyData.Id == 210 || copyData.Id == 98 || copyData.Id == 211)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
				SubsystemSignBlockBehavior signBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemSignBlockBehavior>();
				if (copyData.DirectData != null)
				{
					signBlockBehavior.SetSignData(point, ((SignData)copyData.DirectData).Lines, ((SignData)copyData.DirectData).Colors, ((SignData)copyData.DirectData).Url);
				}
			}
			else if (copyData.Id == 命令方块.Index)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
				SubsystemCommandBlockBehavior commandBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemCommandBlockBehavior>();
				if (copyData.DirectData != null)
				{
					commandBlockBehavior.SetCommandData(point, ((CommandData)copyData.DirectData).Line);
				}
			}
			else if (copyData.Id == 186)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
				SubsystemMemoryBankBlockBehavior bankBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemMemoryBankBlockBehavior>();
				if (copyData.DirectData != null)
				{
					bankBlockBehavior.SetBlockData(point, (MemoryBankData)copyData.DirectData);
				}
			}
			else if (copyData.Id == 227 || copyData.Id == 94 || copyData.Id == 163 || copyData.Id == 164 || copyData.Id == 193 || copyData.Id == 202 || copyData.Id == 31)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
			}
			else if (applyChangeCell)
			{
				SubsystemCommandDef.m_subsystemTerrain.ChangeCell(point.X, point.Y, point.Z, copyData.Value);
			}
			else
			{
				SubsystemCommandDef.m_subsystemTerrain.Terrain.SetCellValueFast(point.X, point.Y, point.Z, copyData.Value);
			}
		}

		public void SetMirrorValue(CopyBlockData blockData, string plane)
		{
			Block block = BlocksManager.Blocks[blockData.Id];
			if (blockData.Id == 227 && blockData.DirectData != null)
			{
				FurnitureDesign design = ((FurnitureDesign)blockData.DirectData).Clone();
				int rotate = FurnitureBlock.GetRotation(blockData.Data);
				rotate = 4 - rotate;
				switch (plane)
				{
					case "xoy": design.Rotate(1, rotate); design.Mirror(0); break;
					case "xoz": design.Rotate(1, rotate); design.Mirror(1); design.Rotate(2, 2); break;
					case "zoy": design.Rotate(1, rotate); design.Mirror(1); break;
					default: break;
				}
				FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
				blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
			}
			else if (block is SlabBlock)
			{
				if (plane == "xoz")
				{
					bool top = SlabBlock.GetIsTop(blockData.Data);
					blockData.Value = Terrain.ReplaceData(blockData.Value, SlabBlock.SetIsTop(blockData.Data, !top));
				}
			}
			else if (block is StairsBlock)
			{
				StairsBlock.CornerType type = StairsBlock.GetCornerType(blockData.Data);
				bool top = StairsBlock.GetIsUpsideDown(blockData.Data);
				int rotate = StairsBlock.GetRotation(blockData.Data);
				if (plane == "xoz")
				{
					blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetIsUpsideDown(blockData.Data, !top));
				}
				else if (plane == "xoy")
				{
					if (type == StairsBlock.CornerType.None)
					{
						switch (rotate)
						{
							case 0: rotate = 2; break;
							case 2: rotate = 0; break;
						}
					}
					else
					{
						switch (rotate)
						{
							case 0: rotate = 3; break;
							case 3: rotate = 0; break;
							case 1: rotate = 2; break;
							case 2: rotate = 1; break;
						}
					}
					blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
				}
				else if (plane == "zoy")
				{
					if (type == StairsBlock.CornerType.None)
					{
						switch (rotate)
						{
							case 1: rotate = 3; break;
							case 3: rotate = 1; break;
						}
					}
					else
					{
						switch (rotate)
						{
							case 0: rotate = 1; break;
							case 1: rotate = 0; break;
							case 2: rotate = 3; break;
							case 3: rotate = 2; break;
						}
					}
					blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
				}
			}
			else if (block is DoorBlock)
			{
				int rotate = DoorBlock.GetRotation(blockData.Data);
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, DoorBlock.SetRotation(blockData.Data, rotate));
			}
			else if (block is LadderBlock)
			{
				int rotate = LadderBlock.GetFace(blockData.Data);
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, LadderBlock.SetFace(blockData.Data, rotate));
			}
			else if (block is TrapdoorBlock)
			{
				if (plane == "xoy")
				{
					int rotate = TrapdoorBlock.GetRotation(blockData.Data);
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
					blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
				}
				else if (plane == "zoy")
				{
					int rotate = TrapdoorBlock.GetRotation(blockData.Data);
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
					blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
				}
				else if (plane == "xoz")
				{
					bool top = TrapdoorBlock.GetUpsideDown(blockData.Data);
					blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetUpsideDown(blockData.Data, !top));
				}
			}
			else if (block is AttachedSignBlock)
			{
				int rotate = AttachedSignBlock.GetFace(blockData.Data);
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, AttachedSignBlock.SetFace(blockData.Data, rotate));
			}
			else if (block is PostedSignBlock)
			{
				int rotate = PostedSignBlock.GetDirection(blockData.Data);
				if (plane == "xoz")
				{
					bool top = PostedSignBlock.GetHanging(blockData.Data);
					blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetHanging(blockData.Data, !top));
				}
				else if (plane == "xoy")
				{
					switch (rotate)
					{
						case 0: rotate = 4; break;
						case 4: rotate = 0; break;
						case 1: rotate = 3; break;
						case 3: rotate = 1; break;
						case 5: rotate = 7; break;
						case 7: rotate = 5; break;
					}
					blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
				}
				else if (plane == "zoy")
				{
					switch (rotate)
					{
						case 1: rotate = 7; break;
						case 7: rotate = 1; break;
						case 2: rotate = 6; break;
						case 6: rotate = 2; break;
						case 3: rotate = 5; break;
						case 5: rotate = 3; break;
					}
					blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
				}
			}
			else if (block is FenceGateBlock)
			{
				int rotate = FenceGateBlock.GetRotation(blockData.Data);
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, FenceGateBlock.SetRotation(blockData.Data, rotate));
			}
			else if (block is DispenserBlock)
			{
				int rotate = DispenserBlock.GetDirection(blockData.Data);
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				else if (plane == "xoz")
				{
					if (rotate == 4) rotate = 5;
					else if (rotate == 5) rotate = 4;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, DispenserBlock.SetDirection(blockData.Data, rotate));
			}
			else if (block is TorchBlock)
			{
				int rotate = blockData.Data;
				if (plane == "xoy")
				{
					if (rotate == 0) rotate = 2;
					else if (rotate == 2) rotate = 0;
				}
				else if (plane == "zoy")
				{
					if (rotate == 1) rotate = 3;
					else if (rotate == 3) rotate = 1;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, rotate);
			}
		}

		public void SetRotateValue(CopyBlockData blockData, string axis, string angle)
		{
			Block block = BlocksManager.Blocks[blockData.Id];
			int angleIndex = 0;
			switch (angle)
			{
				case "+90": angleIndex = 1; break;
				case "+180": angleIndex = 2; break;
				case "+270": angleIndex = 3; break;
				default: break;
			}
			if (blockData.Id == 227 && blockData.DirectData != null)
			{
				FurnitureDesign design = ((FurnitureDesign)blockData.DirectData).Clone();
				int rotate = FurnitureBlock.GetRotation(blockData.Data);
				if (axis == "+x")
				{
					switch (angle)
					{
						case "+90": design.Rotate(0, 3); design.Rotate(2, rotate); break;
						case "+180": design.Rotate(0, 2); design.Rotate(1, rotate); break;
						case "+270": design.Rotate(0, 1); design.Rotate(2, 4 - rotate); break;
						default: break;
					}
					FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
					blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
				}
				else if (axis == "+y")
				{
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, FurnitureBlock.SetRotation(blockData.Data, rotate));
				}
				else if (axis == "+z")
				{
					switch (angle)
					{
						case "+90": design.Rotate(2, 1); design.Rotate(0, rotate); break;
						case "+180": design.Rotate(2, 2); design.Rotate(1, rotate); break;
						case "+270": design.Rotate(2, 3); design.Rotate(0, 4 - rotate); break;
						default: break;
					}
					FurnitureDesign resultDesign = SubsystemCommandDef.m_subsystemFurnitureBlockBehavior.TryAddDesign(design);
					blockData.Value = Terrain.MakeBlockValue(227, 0, FurnitureBlock.SetDesignIndex(0, resultDesign.Index, resultDesign.ShadowStrengthFactor, resultDesign.IsLightEmitter));
				}
			}
			else if (block is StairsBlock)
			{
				StairsBlock.CornerType type = StairsBlock.GetCornerType(blockData.Data);
				int rotate = StairsBlock.GetRotation(blockData.Data);
				if (axis == "+y")
				{
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, StairsBlock.SetRotation(blockData.Data, rotate));
				}
				else if (axis == "+x")
				{
					if (type == StairsBlock.CornerType.None)
					{
						int data = GetIrregularData(new int[4] { 0, 4, 6, 2 }, blockData.Data, angleIndex);
						if (data != -1)
						{
							blockData.Value = Terrain.ReplaceData(blockData.Value, data);
						}
					}
				}
				else if (axis == "+z")
				{
					if (type == StairsBlock.CornerType.None)
					{
						int data = GetIrregularData(new int[4] { 1, 3, 7, 5 }, blockData.Data, angleIndex);
						if (data != -1)
						{
							blockData.Value = Terrain.ReplaceData(blockData.Value, data);
						}
					}
				}
			}
			else if (block is WoodBlock)
			{
				if (axis == "+y")
				{
					if (angleIndex % 2 != 0 && blockData.Data != 0)
					{
						int data = blockData.Data;
						if (data == 1) data = 2;
						else if (data == 2) data = 1;
						blockData.Value = Terrain.ReplaceData(blockData.Value, data);
					}
				}
				else if (axis == "+x")
				{
					if (angleIndex % 2 != 0 && blockData.Data != 2)
					{
						int data = blockData.Data;
						if (data == 0) data = 1;
						else if (data == 1) data = 0;
						blockData.Value = Terrain.ReplaceData(blockData.Value, data);
					}
				}
				else if (axis == "+z")
				{
					if (angleIndex % 2 != 0 && blockData.Data != 1)
					{
						int data = blockData.Data;
						if (data == 0) data = 2;
						else if (data == 2) data = 0;
						blockData.Value = Terrain.ReplaceData(blockData.Value, data);
					}
				}
			}
			else if (block is DoorBlock)
			{
				if (axis == "+y")
				{
					int rotate = DoorBlock.GetRotation(blockData.Data);
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, DoorBlock.SetRotation(blockData.Data, rotate));
				}
			}
			else if (block is LadderBlock)
			{
				if (axis == "+y")
				{
					int rotate = LadderBlock.GetFace(blockData.Data);
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, LadderBlock.SetFace(blockData.Data, rotate));
				}
			}
			else if (block is TrapdoorBlock)
			{
				if (axis == "+y")
				{
					int rotate = TrapdoorBlock.GetRotation(blockData.Data);
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, TrapdoorBlock.SetRotation(blockData.Data, rotate));
				}
			}
			else if (block is AttachedSignBlock)
			{
				if (axis == "+y")
				{
					int rotate = AttachedSignBlock.GetFace(blockData.Data);
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, AttachedSignBlock.SetFace(blockData.Data, rotate));
				}
			}
			else if (block is PostedSignBlock)
			{
				if (axis == "+y")
				{
					int rotate = PostedSignBlock.GetDirection(blockData.Data);
					rotate = (rotate + 8 - 2 * angleIndex) % 8;
					blockData.Value = Terrain.ReplaceData(blockData.Value, PostedSignBlock.SetDirection(blockData.Data, rotate));
				}
			}
			else if (block is FenceGateBlock)
			{
				if (axis == "+y")
				{
					int rotate = FenceGateBlock.GetRotation(blockData.Data);
					rotate = (rotate + 4 - angleIndex) % 4;
					blockData.Value = Terrain.ReplaceData(blockData.Value, FenceGateBlock.SetRotation(blockData.Data, rotate));
				}
			}
			else if (block is DispenserBlock)
			{
				int rotate = DispenserBlock.GetDirection(blockData.Data);
				if (axis == "+y")
				{
					if (rotate >= 0 && rotate < 4) rotate = (rotate + 4 - angleIndex) % 4;
				}
				else if (axis == "+x")
				{
					int newRotate = GetIrregularData(new int[4] { 0, 5, 2, 4 }, rotate, angleIndex);
					if (newRotate != -1) rotate = newRotate;
				}
				else if (axis == "+z")
				{
					int newRotate = GetIrregularData(new int[4] { 1, 4, 3, 5 }, rotate, angleIndex);
					if (newRotate != -1) rotate = newRotate;
				}
				blockData.Value = Terrain.ReplaceData(blockData.Value, DispenserBlock.SetDirection(blockData.Data, rotate));
			}
			else if (block is TorchBlock)
			{
				if (axis == "+y")
				{
					int rotate = blockData.Data;
					if (rotate >= 0 && rotate < 4)
					{
						rotate = (rotate + 4 - angleIndex) % 4;
					}
					blockData.Value = Terrain.ReplaceData(blockData.Value, rotate);
				}
			}
		}

		public int GetIrregularData(int[] adata, int data, int angleIndex)
		{
			for (int a = 0; a < adata.Length; a++)
			{
				if (data == adata[a])
				{
					return adata[(a + angleIndex) % adata.Length];
				}
			}
			return -1;
		}

		public Point3 GetMirrorPoint(Point3 p, Point3 planePoint, string plane, bool laminate)
		{
			Point3 point = Point3.Zero;
			switch (plane)
			{
				case "xoy": point = new Point3(p.X, p.Y, 2 * planePoint.Z - p.Z); break;
				case "xoz": point = new Point3(p.X, 2 * planePoint.Y - p.Y, p.Z); break;
				case "zoy": point = new Point3(2 * planePoint.X - p.X, p.Y, p.Z); break;
				default: break;
			}
			if (laminate)
			{
				switch (plane)
				{
					case "xoy": point.Z = ((point.Z - planePoint.Z) == 0) ? point.Z : ((point.Z - planePoint.Z > 0) ? point.Z - 1 : point.Z + 1); break;
					case "xoz": point.Y = ((point.Y - planePoint.Y) == 0) ? point.Y : ((point.Y - planePoint.Y > 0) ? point.Y - 1 : point.Y + 1); break;
					case "zoy": point.X = ((point.X - planePoint.X) == 0) ? point.X : ((point.X - planePoint.X > 0) ? point.X - 1 : point.X + 1); break;
					default: break;
				}
			}
			return point;
		}

		public Point3 GetRotatePoint(Point3 p, Point3 axisPoint, string axis, string angle)
		{
			Point3 point = Point3.Zero;
			if (axis == "+x")
			{
				switch (angle)
				{
					case "+90": point = new Point3(p.X, axisPoint.Y - p.Z + axisPoint.Z, axisPoint.Z + p.Y - axisPoint.Y); break;
					case "+180": point = new Point3(p.X, 2 * axisPoint.Y - p.Y, 2 * axisPoint.Z - p.Z); break;
					case "+270": point = new Point3(p.X, axisPoint.Y + p.Z - axisPoint.Z, axisPoint.Z - p.Y + axisPoint.Y); break;
					default: break;
				}
			}
			else if (axis == "+y")
			{
				switch (angle)
				{
					case "+90": point = new Point3(axisPoint.X - p.Z + axisPoint.Z, p.Y, axisPoint.Z + p.X - axisPoint.X); break;
					case "+180": point = new Point3(2 * axisPoint.X - p.X, p.Y, 2 * axisPoint.Z - p.Z); break;
					case "+270": point = new Point3(axisPoint.X + p.Z - axisPoint.Z, p.Y, axisPoint.Z - p.X + axisPoint.X); break;
					default: break;
				}
			}
			else if (axis == "+z")
			{
				switch (angle)
				{
					case "+90": point = new Point3(axisPoint.X - p.Y + axisPoint.Y, axisPoint.Y + p.X - axisPoint.X, p.Z); break;
					case "+180": point = new Point3(2 * axisPoint.X - p.X, 2 * axisPoint.Y - p.Y, p.Z); break;
					case "+270": point = new Point3(axisPoint.X + p.Y - axisPoint.Y, axisPoint.Y - p.X + axisPoint.X, p.Z); break;
					default: break;
				}
			}
			return point;
		}

		public void GetCopyExtraData(CopyBlockData copyData, Point3 point)
		{
			if (copyData.Id == 27 || copyData.Id == 45 || copyData.Id == 64 || copyData.Id == 216)
			{
				ComponentBlockEntity blockEntity = SubsystemCommandDef.m_subsystemBlockEntities.GetBlockEntity(point.X, point.Y, point.Z);
				if (blockEntity != null)
				{
					List<ComponentInventoryBase.Slot> inventoryBase = new List<ComponentInventoryBase.Slot>();
					switch (copyData.Id)
					{
						case 27:
							{
								var componentblockEntity = blockEntity.Entity.FindComponent<ComponentCraftingTable>();
								if (componentblockEntity != null)
								{
									foreach (var s in componentblockEntity.m_slots)
									{
										ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
										slot.Count = s.Count;
										slot.Value = s.Value;
										inventoryBase.Add(slot);
									}
								}
								break;
							}
						case 45:
							{
								var componentblockEntity = blockEntity.Entity.FindComponent<ComponentChest>();
								if (componentblockEntity != null)
								{
									foreach (var s in componentblockEntity.m_slots)
									{
										ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
										slot.Count = s.Count;
										slot.Value = s.Value;
										inventoryBase.Add(slot);
									}
								}
								break;
							}
						case 64:
							{
								var componentblockEntity = blockEntity.Entity.FindComponent<ComponentFurnace>();
								if (componentblockEntity != null)
								{
									foreach (var s in componentblockEntity.m_slots)
									{
										ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
										slot.Count = s.Count;
										slot.Value = s.Value;
										inventoryBase.Add(slot);
									}
								}
								break;
							}
						case 216:
							{
								var componentblockEntity = blockEntity.Entity.FindComponent<ComponentDispenser>();
								if (componentblockEntity != null)
								{
									foreach (var s in componentblockEntity.m_slots)
									{
										ComponentInventoryBase.Slot slot = new ComponentInventoryBase.Slot();
										slot.Count = s.Count;
										slot.Value = s.Value;
										inventoryBase.Add(slot);
									}
								}
								break;
							}
						default: break;
					}
					copyData.DirectData = inventoryBase;
					if (HandleExtraData)
					{
						copyData.ExtraData = string.Empty;
						foreach (var ib in inventoryBase)
						{
							copyData.ExtraData += (ib.Value + ":" + ib.Count) + ";";
						}
					}
				}
			}
			else if (copyData.Id == 97 || copyData.Id == 210 || copyData.Id == 98 || copyData.Id == 211)
			{
				SubsystemSignBlockBehavior signBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemSignBlockBehavior>();
				SignData signData = signBlockBehavior.GetSignData(point);
				if (signData != null)
				{
					SignData newSignData = new SignData();
					newSignData.Colors = new Color[signData.Colors.Length];
					newSignData.Lines = new string[signData.Colors.Length];
					newSignData.Url = signData.Url;
					copyData.DirectData = newSignData;
					copyData.ExtraData = string.Empty;
					copyData.ExtraData += "Colors=";
					for (int sc = 0; sc < signData.Colors.Length; sc++)
					{
						newSignData.Colors[sc] = signData.Colors[sc];
						copyData.ExtraData += signData.Colors[sc].ToString() + ";";
					}
					copyData.ExtraData += "&Lines=";
					for (int sc = 0; sc < signData.Lines.Length; sc++)
					{
						newSignData.Lines[sc] = signData.Lines[sc];
						copyData.ExtraData += signData.Lines[sc] + ";";
					}
					copyData.ExtraData += "&Url=" + signData.Url;
				}
			}
			else if (copyData.Id == 命令方块.Index)
			{
				SubsystemCommandBlockBehavior commandBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemCommandBlockBehavior>();
				CommandData commandData = commandBlockBehavior.GetCommandData(point);
				if (commandData != null)
				{
					CommandData newCommandData = new CommandData(point, commandData.Line);
					newCommandData.TrySetValue();
					copyData.DirectData = newCommandData;
					copyData.ExtraData = commandData.Line;
				}
			}
			else if (copyData.Id == 186)
			{
				SubsystemMemoryBankBlockBehavior bankBlockBehavior = SubsystemCommandDef.Project.FindSubsystem<SubsystemMemoryBankBlockBehavior>();
				MemoryBankData memoryBankData = bankBlockBehavior.GetBlockData(point);
				if (memoryBankData != null)
				{
					MemoryBankData newMemoryBankData = (MemoryBankData)memoryBankData.Copy();
					copyData.DirectData = newMemoryBankData;
					if (HandleExtraData)
					{
						copyData.ExtraData = newMemoryBankData.SaveString();
					}
				}
			}
			else if (copyData.Id == 227)
			{
				int fid = FurnitureBlock.GetDesignIndex(copyData.Data);
				FurnitureDesign design = SubsystemCommandDef.Project.FindSubsystem<SubsystemFurnitureBlockBehavior>().GetDesign(fid);
				copyData.DirectData = design.Clone();
				if (HandleExtraData)
				{
					//copyData.ExtraData = design.ToString();
				}
			}
		}

		public List<FurnitureDesign> SortFurniture()
		{
			List<FurnitureDesign> allFurnitures = new List<FurnitureDesign>();
			List<FurnitureDesign> sortFurnitures = new List<FurnitureDesign>();
			foreach (var copydata in CopyBlockDatas.Keys)
			{
				if (CopyBlockDatas[copydata].Id == 227)
				{
					if (CopyBlockDatas[copydata].DirectData != null)
					{
						allFurnitures.Add((FurnitureDesign)CopyBlockDatas[copydata].DirectData);
					}
				}
			}
			int k = 1;
			foreach (FurnitureDesign furniture in allFurnitures)
			{
				bool exist = false;
				foreach (FurnitureDesign furniture2 in sortFurnitures)
				{
					if (furniture.Compare(furniture2))
					{
						furniture.Index = furniture2.Index;
						exist = true;
						break;
					}
				}
				if (!exist)
				{
					furniture.Index = k;
					sortFurnitures.Add(furniture);
					k++;
				}
			}
			return sortFurnitures;
		}
	}
}

namespace Command
{
	public class ClayBlock : Game.ClayBlock, IPaintableBlock
	{
		public new const int Index = 72;

		public static string CommandCategory = "命令方块彩色黏土";

		public override int GetFaceTextureSlot(int face, int value)
		{
			Color clayColor = GetCommandColor(Terrain.ExtractData(value));
			if (!IsColored(Terrain.ExtractData(value)) && IsDefaultColor(clayColor))
			{
				return DefaultTextureSlot;
			}
			return 15;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				List<int> creativeValues = new List<int>();
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
				return creativeValues;
			}
			else
			{
				return base.GetCreativeValues();
			}
		}

		public override string GetCategory(int value)
		{
			int data = Terrain.ExtractData(value);
			if (SubsystemCommandDef.DisplayColorBlock && !IsDefaultColor(GetCommandColor(data)))
			{
				return CommandCategory;
			}
			return base.GetCategory(value);
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			int data = Terrain.ExtractData(value);
			Color clayColor = GetCommandColor(data);
			if (IsDefaultColor(clayColor))
			{
				clayColor = SubsystemPalette.GetColor(generator, GetColor(data));
			}
			Color color = clayColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.OpaqueSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			int data = Terrain.ExtractData(value);
			Color clayColor = GetCommandColor(data);
			if (IsDefaultColor(clayColor))
			{
				clayColor = SubsystemPalette.GetColor(environmentData, GetColor(data));
			}
			color *= clayColor;
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			int data = Terrain.ExtractData(value);
			Color clayColor = GetCommandColor(data);
			if (IsDefaultColor(clayColor))
			{
				clayColor = SubsystemPalette.GetColor(subsystemTerrain, GetColor(data));
			}
			Color color = clayColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(0, value));
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			int data = Terrain.ExtractData(oldValue);
			Color clayColor = GetCommandColor(data);
			if (GetColor(data).HasValue || !IsDefaultColor(clayColor))
			{
				showDebris = true;
				if (toolLevel >= RequiredToolLevel)
				{
					dropValues.Add(new BlockDropValue
					{
						Value = Terrain.MakeBlockValue(DefaultDropContent, 0, data),
						Count = (int)DefaultDropCount
					});
				}
			}
			else
			{
				base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
			}
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}

		public new int Paint(SubsystemTerrain terrain, int value, int? color)
		{
			value = SetCommandColor(value, new Color(15, 15, 15));
			int data = Terrain.ExtractData(value);
			return Terrain.ReplaceData(value, SetColor(data, color));
		}
	}

	public class MimosaLeavesBlock : Game.MimosaLeavesBlock
	{
		public new const int Index = 256;

		public static string CommandCategory = "命令方块彩色金合欢叶";

		public MimosaLeavesBlock()
		{
			m_blockColorsMap = BlockColorsMap.MimosaLeavesColorsMap;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			if (m_random.Bool(0.15f))
			{
				dropValues.Add(new BlockDropValue
				{
					Value = 23,
					Count = 1
				});
				showDebris = true;
			}
			else
			{
				Color leavesColor = GetCommandColor(Terrain.ExtractData(oldValue));
				if (IsDefaultColor(leavesColor))
				{
					base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
				}
				else
				{
					dropValues.Add(new BlockDropValue
					{
						Value = oldValue,
						Count = 1
					});
					showDebris = true;
				}
			}
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(generator.Terrain, x, y, z);
			}
			Color color = leavesColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.AlphaTestSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				color *= m_blockColorsMap.Lookup(environmentData.Temperature, environmentData.Humidity);
			}
			else
			{
				color = leavesColor;
			}
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
			}
			Color color = leavesColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}

	public class OakLeavesBlock : Game.OakLeavesBlock
	{
		public new const int Index = 12;

		public static string CommandCategory = "命令方块彩色橡树叶";

		public OakLeavesBlock()
		{
			m_blockColorsMap = BlockColorsMap.OakLeavesColorsMap;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			if (m_random.Bool(0.15f))
			{
				dropValues.Add(new BlockDropValue
				{
					Value = 23,
					Count = 1
				});
				showDebris = true;
			}
			else
			{
				Color leavesColor = GetCommandColor(Terrain.ExtractData(oldValue));
				if (IsDefaultColor(leavesColor))
				{
					base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
				}
				else
				{
					dropValues.Add(new BlockDropValue
					{
						Value = oldValue,
						Count = 1
					});
					showDebris = true;
				}
			}
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(generator.Terrain, x, y, z);
			}
			Color color = leavesColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.AlphaTestSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				color *= m_blockColorsMap.Lookup(environmentData.Temperature, environmentData.Humidity);
			}
			else
			{
				color = leavesColor;
			}
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
			}
			Color color = leavesColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}

	public class SpruceLeavesBlock : Game.SpruceLeavesBlock
	{
		public new const int Index = 14;

		public static string CommandCategory = "命令方块彩色云杉叶";

		public SpruceLeavesBlock()
		{
			m_blockColorsMap = BlockColorsMap.SpruceLeavesColorsMap;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			if (m_random.Bool(0.15f))
			{
				dropValues.Add(new BlockDropValue
				{
					Value = 23,
					Count = 1
				});
				showDebris = true;
			}
			else
			{
				Color leavesColor = GetCommandColor(Terrain.ExtractData(oldValue));
				if (IsDefaultColor(leavesColor))
				{
					base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
				}
				else
				{
					dropValues.Add(new BlockDropValue
					{
						Value = oldValue,
						Count = 1
					});
					showDebris = true;
				}
			}
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(generator.Terrain, x, y, z);
			}
			Color color = leavesColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.AlphaTestSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				color *= m_blockColorsMap.Lookup(environmentData.Temperature, environmentData.Humidity);
			}
			else
			{
				color = leavesColor;
			}
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
			}
			Color color = leavesColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}

	public class TallSpruceLeavesBlock : Game.TallSpruceLeavesBlock
	{
		public new const int Index = 225;

		public static string CommandCategory = "命令方块彩色高云杉叶";

		public TallSpruceLeavesBlock()
		{
			m_blockColorsMap = BlockColorsMap.TallSpruceLeavesColorsMap;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			if (m_random.Bool(0.15f))
			{
				dropValues.Add(new BlockDropValue
				{
					Value = 23,
					Count = 1
				});
				showDebris = true;
			}
			else
			{
				Color leavesColor = GetCommandColor(Terrain.ExtractData(oldValue));
				if (IsDefaultColor(leavesColor))
				{
					base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
				}
				else
				{
					dropValues.Add(new BlockDropValue
					{
						Value = oldValue,
						Count = 1
					});
					showDebris = true;
				}
			}
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(generator.Terrain, x, y, z);
			}
			Color color = leavesColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.AlphaTestSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				color *= m_blockColorsMap.Lookup(environmentData.Temperature, environmentData.Humidity);
			}
			else
			{
				color = leavesColor;
			}
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
			}
			Color color = leavesColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}

	public class BirchLeavesBlock : Game.BirchLeavesBlock
	{
		public new const int Index = 13;

		public static string CommandCategory = "命令方块彩色白桦叶";

		public BirchLeavesBlock()
		{
			m_blockColorsMap = BlockColorsMap.BirchLeavesColorsMap;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 32 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			if (m_random.Bool(0.15f))
			{
				dropValues.Add(new BlockDropValue
				{
					Value = 23,
					Count = 1
				});
				showDebris = true;
			}
			else
			{
				Color leavesColor = GetCommandColor(Terrain.ExtractData(oldValue));
				if (IsDefaultColor(leavesColor))
				{
					base.GetDropValues(subsystemTerrain, oldValue, newValue, toolLevel, dropValues, out showDebris);
				}
				else
				{
					dropValues.Add(new BlockDropValue
					{
						Value = oldValue,
						Count = 1
					});
					showDebris = true;
				}
			}
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(generator.Terrain, x, y, z);
			}
			Color color = leavesColor;
			generator.GenerateCubeVertices(this, value, x, y, z, color, geometry.AlphaTestSubsetsByFace);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				color *= m_blockColorsMap.Lookup(environmentData.Temperature, environmentData.Humidity);
			}
			else
			{
				color = leavesColor;
			}
			BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color leavesColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(leavesColor))
			{
				leavesColor = m_blockColorsMap.Lookup(subsystemTerrain.Terrain, Terrain.ToCell(position.X), Terrain.ToCell(position.Y), Terrain.ToCell(position.Z));
			}
			Color color = leavesColor;
			return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, color, GetFaceTextureSlot(4, value));
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			return Terrain.ReplaceData(value, colorData);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}

	public class GlassBlock : Game.GlassBlock
	{
		public new const int Index = 15;

		public static string CommandCategory = "命令方块彩色玻璃";

		public Texture2D Texture;

		public override void Initialize()
		{
			Texture = ContentManager.Get<Texture2D>("Textures/Glass");
		}

		public override int GetFaceTextureSlot(int face, int value)
		{
			int data = Terrain.ExtractData(value);
			Color glassColor = GetCommandColor(data);
			if (IsDefaultColor(glassColor))
			{
				return base.GetFaceTextureSlot(face, value);
			}
			else
			{
				return GetCommandColorAlpha(data);
			}
		}

		public override int GetTextureSlotCount(int value)
		{
			Color glassColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(glassColor))
			{
				return base.GetTextureSlotCount(value);
			}
			return 4;
		}

		public override IEnumerable<int> GetCreativeValues()
		{
			List<int> creativeValues = new List<int>();
			if (SubsystemCommandDef.DisplayColorBlock)
			{
				for (int i = 0; i < 4096; i++)
				{
					creativeValues.Add(Index + i * 40 * 16384);
				}
			}
			else
			{
				creativeValues.Add(Index);
			}
			return creativeValues;
		}

		public override BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
		{
			Color glassColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(glassColor))
			{
				return base.CreateDebrisParticleSystem(subsystemTerrain, position, value, strength);
			}
			else
			{
				return new BlockDebrisParticleSystem(subsystemTerrain, position, strength, DestructionDebrisScale, glassColor, GetFaceTextureSlot(0, value), Texture);
			}
		}

		public override string GetCategory(int value)
		{
			if (SubsystemCommandDef.DisplayColorBlock && value != Index) return CommandCategory;
			return base.GetCategory(value);
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			Color glassColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(glassColor))
			{
				generator.GenerateCubeVertices(this, value, x, y, z, Color.White, geometry.AlphaTestSubsetsByFace);
			}
			else
			{
				generator.GenerateCubeVertices(this, value, x, y, z, glassColor, geometry.GetGeometry(Texture).TransparentSubsetsByFace);
			}
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			Color glassColor = GetCommandColor(Terrain.ExtractData(value));
			if (IsDefaultColor(glassColor))
			{
				BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, color, color, environmentData);
			}
			else
			{
				BlocksManager.DrawCubeBlock(primitivesRenderer, value, new Vector3(size), ref matrix, glassColor, glassColor, environmentData, Texture);
			}
		}

		public static Color GetCommandColor(int data)
		{
			int colorData = (data >> 5) & 0xFFF;
			int R = (colorData >> 8) & 0xF;
			int G = (colorData >> 4) & 0xF;
			int B = (colorData & 0xF);
			return new Color(R * 16, G * 16, B * 16) + new Color(15, 15, 15);
		}

		public static int SetCommandColor(int value, Color color)
		{
			int data = Terrain.ExtractData(value);
			color -= new Color(15, 15, 15);
			int R = (int)(color.R / 16f) << 8;
			int G = (int)(color.G / 16f) << 4;
			int B = (int)(color.B / 16f);
			int colorData = ((R | G | B) & 0xFFF) << 5;
			data = (data & -131041) | colorData;
			return Terrain.ReplaceData(value, data);
		}

		public static int GetCommandColorAlpha(int data)
		{
			return (data >> 1) & 0xF;
		}

		public static int SetCommandColorAlpha(int value, int alpha)
		{
			int data = Terrain.ExtractData(value);
			alpha = (alpha & 0xF) << 1;
			data = (data & -31) | alpha;
			return Terrain.ReplaceData(value, data);
		}

		public static bool IsDefaultColor(Color color)
		{
			return color.R == 15 && color.G == 15 && color.B == 15;
		}
	}
}